文章目录
- 解决方案: 升级swoole至最新
- 场景: 当前有数据1,2,3投入队列,假设1,2,3都有创建的需求,投递至1时开启事务,并在未提交时,出现异常抛出了throw。此时数据2又进行消费执行创建,此时数据2会创建成功吗? 框架分别的处理方案: laravel:数据2不会创建成功,并且会影响之后的所有数据的创建 hyperf:数据2创建成功,并在终端抛出您可能上一个事务未回滚的提醒,并且执行了一次回滚操作。 为什么? laravel框架消费时为线性消费,例如运用了supervisor,第一次事务未关闭影响第二次消费的事务,这是由于抛异常时没有及时回滚事务所导致的。 hyperf在消费时会新建新的协程进行操作,使用create 或者 Parallel进行创建新的协程进行消费,在DBconnect中会判断当前协程是否已经有链接,如果检查到有链接会调用defer进行release操作,判断是否在事务内,如果在,则立即回滚 解决方案: laravel中,在providers/EventServiceProvide 的$listen 中 监听 JobProcessed 和 JobExceptionOccured 这两个分别为job执行成功和失败的操作。建立QueueRollbackListener。写入以下代码:public function handle() { connection = Db::connection(); if (connection->transactionLevel() > 0) { $connection->rollback(0); } }
- 场景: 在返回前端内容需要输出 header1:1, header:2的情况 处理: hyperf的处理,会以header1:1:2的情况展示,然后可以前端分割处理 更好的解决方案 swoole4.6+ 通过重写ResponseEmitter 类 中 buildSwooleResopnse,修改类映射config/dependencies.php中将 ResponseEmitter接管到新重构后的类中,在buildSwooleResopnse 中删除implode(':', $value);修改为$swooleResponse->header($key, $value);
- 案例原因 父协程由于没有阻塞操作,执行完进行了释放 解决方案 使用waitgroup,Parallel等内容进行阻塞<?php use HyperfUtilsExceptionParallelExecutionException; use HyperfUtilsCoroutine; use HyperfUtilsParallel;parallel = new Parallel();parallel->add(function () { sleep(1); return Coroutine::id(); }); parallel->add(function () { sleep(1); return Coroutine::id(); });try{ //results 结果为 [1, 2] results =parallel->wait(); } catch(ParallelExecutionException e){ //e->getResults() 获取协程中的返回值。 // $e->getThrowables() 获取协程中出现的异常。 }
- 文档:https://hyperf.wiki/2.1/#/zh-cn/quick-start/questions?id=inject-%e6%88%96-value-%e6%b3%a8%e8%a7%a3%e4%b8%8d%e7%94%9f%e6%95%88
- 文档:https://hyperf.wiki/2.1/#/zh-cn/quick-start/questions?id=%e5%bc%82%e6%ad%a5%e9%98%9f%e5%88%97%e6%b6%88%e6%81%af%e4%b8%a2%e5%a4%b1
- 可以忽略此错误。这个错误就是 socket_buffer_size 选项过大,个别系统不接受,并不影响程序的运行。mac会偶现这种情况,Bsd系统不支持
- 当碰到修改后的代码不生效的问题,请执行以下命令 composer dump-autoload -o开发阶段,请不要设置 scan_cacheable 为 true,它会导致 收集器缓存 存在时,不会再次扫描文件。 当环境变量存在 SCAN_CACHEABLE 时,.env 中无法修改这个配置。
- 执行· COMPOSER_MEMORY_LIMIT=-1 composer install
- 当项目启动时,抛出类似于以下错误时 Fatal error: Uncaught PhpParserError: Syntax error, unexpected T_STRING on line 27 in vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php:315 可以执行脚本 composer analyse,对项目进行静态检测,便可以找到出现问题的代码段
- 因为他会在框架启动前去链接一次
- 例如在处理中间件时忘记注入上下文,导致当前获取的上下文内容不属于此协程
- 会导致与结果不符,可以使用协程上下文Context作为管理。
- 查看终端是否出现报错信息,有则处理 使用lsof -i:端口号查看进程id,kill掉并重启
- 比如你想要的内容与composer依赖包提供的内容不同,可以切入对应类优雅的进行重写方法 新建重写类,然后在config/autoload/dependencies.php中进行替换
- 在传统的 PHP-FPM 的框架里,会习惯提供一个 AbstractController 或其它命名的 Controller 抽象父类,然后定义的 Controller 需要继承它用于获取一些请求数据或进行一些返回操作,在 Hyperf 里是 不能这样做 的,因为在 Hyperf 内绝大部分的对象包括 Controller 都是以 单例(Singleton) 形式存在的,这也是为了更好的复用对象,而对于与请求相关的数据在协程下也是需要储存到 协程上下文(Context) 内的,所以在编写代码时请务必注意 不要 将单个请求相关的数据储存在类属性内,包括非静态属性。 当然如果非要通过类属性来储存请求数据的话,也不是没有办法的,我们可以注意到我们获取 请求(Request) 与 响应(Response) 对象时是通过注入 HyperfHttpServerContractRequestInterface 和 HyperfHttpServerContractResponseInterface 来获取的,那对应的对象不也是个单例吗?这里是如何做到协程安全的呢?就 RequestInterface 来举例,对应的 HyperfHttpServerRequest 对象内部在获取 PSR-7 请求对象 时,都是从 协程上下文(Context) 获取的,所以实际使用的类仅仅是一个代理类,实际调用的都是从 协程上下文(Context) 中获取的。
- 相对路径 DIR 时,会碰到的问题。请尽量使用 BASE_PATH 常量。
- 使用随机数时需要重新播种。也可使用random_int获取真实随机数不需要重新播种
- 例如: values = array_map( static function (value) { return empty(value) ? '""' :value; }, $values );
解决方案: 升级swoole至最新
- 场景: 当前有数据1,2,3投入队列,假设1,2,3都有创建的需求,投递至1时开启事务,并在未提交时,出现异常抛出了throw。此时数据2又进行消费执行创建,此时数据2会创建成功吗?
- 框架分别的处理方案: laravel:数据2不会创建成功,并且会影响之后的所有数据的创建 hyperf:数据2创建成功,并在终端抛出您可能上一个事务未回滚的提醒,并且执行了一次回滚操作。
- 为什么?
- laravel框架消费时为线性消费,例如运用了supervisor,第一次事务未关闭影响第二次消费的事务,这是由于抛异常时没有及时回滚事务所导致的。
- hyperf在消费时会新建新的协程进行操作,使用
create 或者 Parallel进行创建新的协程进行消费,在DBconnect中会判断当前协程是否已经有链接,如果检查到有链接会调用defer进行release操作,判断是否在事务内,如果在,则立即回滚 - 解决方案: laravel中,在
providers/EventServiceProvide 的$listen 中 监听 JobProcessed 和 JobExceptionOccured 这两个分别为job执行成功和失败的操作。建立QueueRollbackListener。写入以下代码:
public function handle()
{
connection = Db::connection();
if (connection->transactionLevel() > 0) {
$connection->rollback(0);
}
}

create 或者 Parallel进行创建新的协程进行消费,在DBconnect中会判断当前协程是否已经有链接,如果检查到有链接会调用defer进行release操作,判断是否在事务内,如果在,则立即回滚providers/EventServiceProvide 的$listen 中 监听 JobProcessed 和 JobExceptionOccured 这两个分别为job执行成功和失败的操作。建立QueueRollbackListener。写入以下代码:public function handle()
{
connection = Db::connection();
if (connection->transactionLevel() > 0) {
$connection->rollback(0);
}
}
- 场景: 在返回前端内容需要输出 header1:1, header:2的情况
- 处理: hyperf的处理,会以header1:1:2的情况展示,然后可以前端分割处理
- 更好的解决方案 swoole4.6+ 通过重写ResponseEmitter 类 中 buildSwooleResopnse,修改类映射
config/dependencies.php中将 ResponseEmitter接管到新重构后的类中,在buildSwooleResopnse 中删除implode(':', $value);修改为$swooleResponse->header($key, $value); 
config/dependencies.php中将 ResponseEmitter接管到新重构后的类中,在buildSwooleResopnse 中删除implode(':', $value);修改为$swooleResponse->header($key, $value); 
- 案例

- 原因 父协程由于没有阻塞操作,执行完进行了释放
- 解决方案 使用
waitgroup,Parallel等内容进行阻塞
<?php
use HyperfUtilsExceptionParallelExecutionException;
use HyperfUtilsCoroutine;
use HyperfUtilsParallel;
parallel = new Parallel();parallel->add(function () {
sleep(1);
return Coroutine::id();
});
parallel->add(function () {
sleep(1);
return Coroutine::id();
});
try{
//results 结果为 [1, 2]
results =parallel->wait();
} catch(ParallelExecutionException e){
//e->getResults() 获取协程中的返回值。
// $e->getThrowables() 获取协程中出现的异常。
}

waitgroup,Parallel等内容进行阻塞<?php
use HyperfUtilsExceptionParallelExecutionException;
use HyperfUtilsCoroutine;
use HyperfUtilsParallel;
parallel = new Parallel();parallel->add(function () {
sleep(1);
return Coroutine::id();
});
parallel->add(function () {
sleep(1);
return Coroutine::id();
});
try{
//results 结果为 [1, 2]
results =parallel->wait();
} catch(ParallelExecutionException e){
//e->getResults() 获取协程中的返回值。
// $e->getThrowables() 获取协程中出现的异常。
}
可以忽略此错误。这个错误就是 socket_buffer_size 选项过大,个别系统不接受,并不影响程序的运行。mac会偶现这种情况,Bsd系统不支持
当碰到修改后的代码不生效的问题,请执行以下命令
composer dump-autoload -o
开发阶段,请不要设置 scan_cacheable 为 true,它会导致 收集器缓存 存在时,不会再次扫描文件。 当环境变量存在 SCAN_CACHEABLE 时,.env 中无法修改这个配置。
执行·
COMPOSER_MEMORY_LIMIT=-1 composer install
当项目启动时,抛出类似于以下错误时
Fatal error: Uncaught PhpParserError: Syntax error, unexpected T_STRING on line 27 in vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php:315 可以执行脚本 composer analyse,对项目进行静态检测,便可以找到出现问题的代码段
因为他会在框架启动前去链接一次
例如在处理中间件时忘记注入上下文,导致当前获取的上下文内容不属于此协程
会导致与结果不符,可以使用协程上下文Context作为管理。
- 查看终端是否出现报错信息,有则处理
- 使用
lsof -i:端口号查看进程id,kill掉并重启
lsof -i:端口号查看进程id,kill掉并重启 - 比如你想要的内容与composer依赖包提供的内容不同,可以切入对应类优雅的进行重写方法
- 新建重写类,然后在
config/autoload/dependencies.php中进行替换
config/autoload/dependencies.php中进行替换在传统的 PHP-FPM 的框架里,会习惯提供一个 AbstractController 或其它命名的 Controller 抽象父类,然后定义的 Controller 需要继承它用于获取一些请求数据或进行一些返回操作,在 Hyperf 里是 不能这样做 的,因为在 Hyperf 内绝大部分的对象包括 Controller 都是以 单例(Singleton) 形式存在的,这也是为了更好的复用对象,而对于与请求相关的数据在协程下也是需要储存到 协程上下文(Context) 内的,所以在编写代码时请务必注意 不要 将单个请求相关的数据储存在类属性内,包括非静态属性。
当然如果非要通过类属性来储存请求数据的话,也不是没有办法的,我们可以注意到我们获取 请求(Request) 与 响应(Response) 对象时是通过注入 HyperfHttpServerContractRequestInterface 和 HyperfHttpServerContractResponseInterface 来获取的,那对应的对象不也是个单例吗?这里是如何做到协程安全的呢?就 RequestInterface 来举例,对应的 HyperfHttpServerRequest 对象内部在获取 PSR-7 请求对象 时,都是从 协程上下文(Context) 获取的,所以实际使用的类仅仅是一个代理类,实际调用的都是从 协程上下文(Context) 中获取的。
相对路径 DIR 时,会碰到的问题。请尽量使用 BASE_PATH 常量。
使用随机数时需要重新播种。也可使用random_int获取真实随机数不需要重新播种
例如:
values = array_map(
static function (value) {
return empty(value) ? '""' :value;
}, $values
);



