/**
  * <p> Only use if you require exact peak memory usage etc.
  * for certain invocations.
  *
  * <p> This method may fail if shared memory is getting unavailable due to
  * size of (in-)directly passed object(s).
  *
  * <p> Invocations that directly rely on reflections may not work properly.
  *
  * <p> Forked profiling requries PHP compiled with shared memory support
  * [--enable-sysvshm] and enabled extension [pcntl].
  *
  * @return \Components\Debug_Profiler
  */
 public static function profileCallForked(array $callable_, array $args_ = [])
 {
     if (false === static::isForkedProfilingSupported() || false === Memory_Shared_Shm::isSupported()) {
         throw new Exception_NotSupported('debug/profiler', 'Forked profiling is not supported on this platform\'s configuration.');
     }
     if (false === is_callable($callable_)) {
         throw new Exception_IllegalArgument('debug/profiler', 'Valid callback expected.');
     }
     $shm = Memory_Shared_Shm_Temporary::create();
     $shm->attach();
     self::$m_profileForkedArgs = $args_;
     self::$m_profileForkedCallable = $callable_;
     self::$m_profileForkedSegmentId = $shm->getSegmentId();
     $pid = pcntl_fork();
     if (-1 == $pid) {
         throw new Exception_IllegalState('debug/profiler', 'Unable to fork child process. Forked profiling failed.');
     }
     if ($pid) {
         $pid = pcntl_wait($status);
     } else {
         ob_start();
         $sessionId = static::start();
         try {
             $returnValue = call_user_func_array(self::$m_profileForkedCallable, self::$m_profileForkedArgs);
             $profiler = static::stop($sessionId);
             $profiler->m_returnValue = $returnValue;
         } catch (\ErrorException $e) {
             $profiler = static::stop($sessionId);
             $profiler->m_exception = Exception_Flat::create($e);
         } catch (\Exception $e) {
             $profiler = static::stop($sessionId);
             $profiler->m_exception = Exception_Flat::create($e);
         }
         self::$m_profileForkedArgs = null;
         self::$m_profileForkedCallable = null;
         $segment = Memory_Shared_Shm::forSegment(self::$m_profileForkedSegmentId);
         $segment->attach();
         $segment->set(1, ob_get_clean());
         $segment->set(2, $profiler->result()->m_exception);
         $segment->set(3, $profiler->result()->m_memoryConsumptionAfter);
         $segment->set(4, $profiler->result()->m_memoryConsumptionBefore);
         $segment->set(5, $profiler->result()->m_memoryConsumptionPeak);
         $segment->set(6, $profiler->result()->m_posixSystemTime);
         $segment->set(7, $profiler->result()->m_posixUserTime);
         $segment->set(8, $profiler->result()->m_returnValue);
         $segment->set(9, $profiler->result()->m_timeStart);
         $segment->set(10, $profiler->result()->m_timeStop);
         $segment->set(11, $profiler->result()->m_splitTimeTable);
         exit(0);
     }
     echo $shm->get(1);
     $profiler = new static();
     $profiler->m_profiling = false;
     $profiler->m_exception = $shm->get(2);
     $profiler->m_memoryConsumptionAfter = $shm->get(3);
     $profiler->m_memoryConsumptionBefore = $shm->get(4);
     $profiler->m_memoryConsumptionPeak = $shm->get(5);
     $profiler->m_posixSystemTime = $shm->get(6);
     $profiler->m_posixUserTime = $shm->get(7);
     $profiler->m_returnValue = $shm->get(8);
     $profiler->m_timeStart = $shm->get(9);
     $profiler->m_timeStop = $shm->get(10);
     $profiler->m_splitTimeTable = $shm->get(11);
     $shm->clear();
     return $profiler;
 }
 public function __call($key_, $args_)
 {
     if (null === ($method = $this->getMethod($key_))) {
         return null;
     }
     // FIXME Re-integrate profiling.
     $profileMethod = 'profileCall';
     if (Test_Profiler::isForkedProfilingSupported() && array_key_exists($method->name, $this->m_profileMethodsForked)) {
         $profileMethod = 'profileCallForked';
     }
     ob_start();
     $returnValue = null;
     if (true === array_key_exists($method->name, $this->m_profileMethods)) {
         $this->m_profileMethods[$method->name] = Test_Profiler::$profileMethod([$this->m_instance, $this->m_methods[$method->name]->name]);
         $this->m_exceptions[$method->name] = $this->m_profileMethods[$method->name]->exception();
         $returnValue = $this->m_profileMethods[$method->name]->returnValue();
     } else {
         try {
             if ($this->m_methods[$method->name]->isStatic()) {
                 $returnValue = $this->m_methods[$method->name]->invoke($this->m_class);
             } else {
                 $returnValue = $this->m_instance->{$this->m_methods[$method->name]->name}();
             }
         } catch (\Exception $e) {
             $this->m_exceptions[$method->name] = Exception_Flat::create($e);
         }
     }
     $this->m_failed[$method->name] = true;
     if (false === isset($this->m_exceptionsExpected[$method->name]) && false === isset($this->m_exceptions[$method->name])) {
         $this->m_failed[$method->name] = false;
     } else {
         if (isset($this->m_exceptionsExpected[$method->name]) && isset($this->m_exceptions[$method->name])) {
             if ($this->m_exceptionsExpected[$method->name] == $this->m_exceptions[$method->name]->type) {
                 $this->m_failed[$method->name] = false;
             } else {
                 $exceptionReflection = new \ReflectionClass($this->m_exceptions[$method->name]);
                 if ($exceptionReflection->isSubclassOf($this->m_exceptionsExpected[$method->name])) {
                     $this->m_failed[$method->name] = false;
                 }
             }
         }
     }
     if (trim($output = ob_get_clean())) {
         $this->m_output[$method->name] = $output;
     }
     return $returnValue;
 }