在Hyperf官方文档的服务器要求中提到
Swoole PHP 扩展 >= 4.5,并关闭了 Short Name
并且,在文档的常见问题中也会看到Swoole 短名未关闭这一个tag。
我想问了,那为什么hyperf一定要关闭掉Swoole的协程短名称呢
首先,我们先看一下什么是Swoole的协程短名称
所有的 Swoole\Coroutine 前缀的类名映射为 Co。此外还有下面的一些映射:创建协程 go() 函数,通道操作 chan() 函数,延迟执行 defer() 函数
从上面的解释我们知道了,hyperf主要就是不想让我们使用以上这几个函数,但是为啥不让我们使用的呢?想到之前在代码中经常使用go()函数来解决代码中的阻塞问题,难道说我写的代码并没有协程化?在Hyperf经过测试之后发现,go()函数协程话确实是生效的,那究竟是什么让本来已经被禁用的go()函数又“复活”了呢?
在phpStrom只点击go()函数我们跳转到了vendor/hyperf/utils/src/Functions.php文件,该文件是在composer.json中指定的自动化加载文件
if (! function_exists('go')) {
/**
* @return bool|int
*/
function go(callable $callable)
{
$id = Coroutine::create($callable);
return $id > 0 ? $id : false;
}
}
如果框架里没定义go()函数的话,就会执行这里的逻辑去调用Coroutine::create($callable),注意这里的Coroutine类并不是Swoole\Coroutine,而是vendor/hyperf/utils/src/Coroutine.php
public static function create(callable $callable): int
{
$result = SwooleCoroutine::create(function () use ($callable) {
try {
call($callable);
} catch (Throwable $throwable) {
if (ApplicationContext::hasContainer()) {
$container = ApplicationContext::getContainer();
if ($container->has(StdoutLoggerInterface::class)) {
/* @var LoggerInterface $logger */
$logger = $container->get(StdoutLoggerInterface::class);
/* @var FormatterInterface $formatter */
if ($container->has(FormatterInterface::class)) {
$formatter = $container->get(FormatterInterface::class);
$logger->warning($formatter->format($throwable));
} else {
$logger->warning(sprintf('Uncaptured exception[%s] detected in %s::%d.', get_class($throwable), $throwable->getFile(), $throwable->getLine()));
}
}
}
}
});
return is_int($result) ? $result : -1;
}
可以看到,我们“劫持”了go()函数,给他做了一些改动,捕获了创建协程时抛出的异常,将异常打印到控制台上。(注:对于Coroutine::create方式创建的协程在callable中存在异常时会抛出Fatal error,这是我们不愿意看到的)。
所以,到这里我们似乎理解了为什么Hyperf要关闭Swoole的短名称,目的就是劫持go()、co()函数来捕获callable的异常避免进程抛出Fatal error
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。