public function send(StreamInterface $stream) { if (!$stream->isWritable()) { throw new \InvalidArgumentException('Output stream must be writable'); } if (is_array($this->callback)) { $ref = (new \ReflectionClass(is_object($this->callback[0]) ? get_class($this->callback[0]) : $this->callback[0]))->getMethod($this->callback[1]); } elseif (is_object($this->callback) && !$this->callback instanceof \Closure) { $ref = new \ReflectionMethod(get_class($this->callback), '__invoke'); } else { $ref = new \ReflectionFunction($this->callback); } if ($ref->isGenerator()) { foreach (call_user_func($this->callback) as $chunk) { $stream->write($chunk); } return; } foreach ($ref->getParameters() as $param) { if (NULL !== ($type = $param->getClass())) { if ($type->name === StreamInterface::class || $type->implementsInterface(StreamInterface::class)) { call_user_func($this->callback, $stream); return; } } break; } $stream->write((string) call_user_func($this->callback)); }
function wrap($handler) { if (class_exists("\\Generator") && is_callable($handler)) { if (is_array($handler)) { $m = new ReflectionMethod($handler[0], $handler[1]); } else { $m = new ReflectionFunction($handler); } if ($m->isGenerator()) { return function () use($handler) { return all(func_get_args())->then(function ($args) use($handler) { array_splice($args, 0, 0, array($handler)); return call_user_func_array('\\Hprose\\Future\\co', $args); }); }; } } if (is_object($handler)) { if (is_callable($handler)) { return new CallableWrapper($handler); } return new Wrapper($handler); } if (is_callable($handler)) { return function () use($handler) { return all(func_get_args())->then(function ($args) use($handler) { return call_user_func_array($handler, $args); }); }; } return $handler; }
}; $rf1 = new ReflectionFunction($closure1); var_dump($rf1->isGenerator()); $rf2 = new ReflectionFunction($closure2); var_dump($rf2->isGenerator()); function func1() { return 'func1'; } function func2() { (yield 'func2'); } $rf1 = new ReflectionFunction('func1'); var_dump($rf1->isGenerator()); $rf2 = new ReflectionFunction('func2'); var_dump($rf2->isGenerator()); class Foo { public function f1() { } public function f2() { yield; } } $rc = new ReflectionClass('Foo'); foreach ($rc->getMethods() as $m) { var_dump($m->isGenerator()); }
public function addFunction($func, $alias = '', array $options = array()) { if (!is_callable($func)) { throw new Exception('Argument func must be callable.'); } if (is_array($alias) && empty($options)) { $options = $alias; $alias = ''; } if (empty($alias)) { if (is_string($func)) { $alias = $func; } elseif (is_array($func)) { $alias = $func[1]; } else { throw new Exception('Need an alias'); } } $name = strtolower($alias); if (!array_key_exists($name, $this->calls)) { $this->names[] = $alias; } if (class_exists("\\Generator")) { if (is_array($func)) { $f = new ReflectionMethod($func[0], $func[1]); } else { $f = new ReflectionFunction($func); } if ($f->isGenerator()) { $func = wrap($func); } } $call = new stdClass(); $call->method = $func; $call->mode = isset($options['mode']) ? $options['mode'] : ResultMode::Normal; $call->simple = isset($options['simple']) ? $options['simple'] : null; $call->oneway = isset($options['oneway']) ? $options['oneway'] : false; $call->async = isset($options['async']) ? $options['async'] : false; $call->passContext = isset($options['passContext']) ? $options['passContext'] : null; $this->calls[$name] = $call; return $this; }