PHP-MSF源码中长尾函数如何详细解析与实现?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1816个文字,预计阅读时间需要8分钟。
我们来看一下分享的伪原创内容:
原文:我们来分享一下整体源码:php-msf:https://github.com/pinguo/php-msf 源码解读也做了一段时期了,总结一下自己的心得:抓住生命周期,让代码在你的脑海中跑起来,分析架构,关键字,分层,边界
伪原创:分享整体源码资源:php-msf,链接为:https://github.com/pinguo/php-msf。对其源码进行解读已有段时间,个人感悟如下:紧握生命周期,使代码在心中活跃,深入分析架构、关键词、分层及边界。
我们来看分享下具体源码:php-msf:github.com/pinguo/php-msf
源码解读也做了一段时间了, 总结一下自己的心得:
抓住 生命周期, 让代码在你脑海中 跑起来
分析架构, 关键字 分层 边界 隔离
一个好的框架, 弄清楚 生命周期 和 架构, 基本就已经到了 熟悉 的状态了, 之后是填充细节和编码熟练了
这里再介绍几个次重要的心得:
弄明白这个工具擅长干什么, 适合干什么. 这个信息也非常容易获取到, 工具的文档通常都会显眼标注出来, 可以通过这些 功能/特性, 尝试以点见面
从工程化的角度去看这个项目, 主要和上面的 架构 区分, 在处理核心业务, 也就是上面的 功能/特性 外, 工程化还涉及到 安全/测试/编码规范/语言特性 等方面, 这些也是平时在写业务代码时思考较少并且实践较少的部分
工具的使用, 推荐我现在使用的组合: phpstorm + 百度脑图 + Markdown笔记 + blog和 php-msf 的渊源等写技术生活相关的 blog 再来和大家八, 直接上菜.
生命周期 & 架构
官方文档制作了一张非常好的图: 处理请求流程图. 推荐各位同仁, 有闲暇时制作类似的图, 对思维很有的帮助.
根据这张图来思考 生命周期 & 架构, 这里就不赘述了, 这里分析一下 msf 中一些技术点:
协程相关知识
msf 中技术点摘录
协程
我会用我的方式来讲解, 如果需要深入了解的, 可以看我后面推荐的资源.
类 vs 对象 是一组很重要的概念. 类代表我们对事物的抽象, 这个抽象的能力在我们以后会一直用到, 希望大家有意识的培养这方面的意识, 至少可以起到触类旁通的作用. 对象是 实例化 的类, 是 真正干活的, 我们要讨论的 协程, 就是这样一个 真正干活的 角色.
协程从哪里来, 到哪里去, 它是干什么的?
想一想这几个简单的问题, 也许你对协程的理解就更深刻了, 记住这几个关键词:
产生. 需要有地方来产生协程, 你可能不需要知道细节, 但是需要知道什么时候发生了
调度. 肯定是有很多协程一起工作的, 所以需要调度, 怎么调度的呢?
销毁. 是否会销毁? 什么时候销毁?
现在, 我们再来看看协程的使用方式对比, 这里注意一下, 我没有用 协程的实现方式对比, 因为很多时候, 需求实际是这样的:
怎么实现我不管, 我选最好用的.
// msf - 单次协程调度 $response = yield $this->getRedisPool('tw')->get('apiCacheForABCoroutine'); // msf - 并发协程调用 $client1 = $this->getObject(Client::class, ['www.baidu.com/']); yield $client1->goDnsLookup(); $client2 = $this->getObject(Client::class, ['www.qq.com/']); yield $client2->goDnsLookup(); $result[] = yield $client1->goGet('/'); $result[] = yield $client2->goGet('/');
大致 是这样的一个等式: 使用协程 = 加上 yield, 所以搞清楚哪些地方需要加上 yield 就好了 -- 有阻塞IO的地方, 比如 文件IO, 网络IO(redis/mysql/pecl.php.net/package/aop
PHP-AOP扩展介绍 | rango: rango.swoole.com/archives/83
AOP, 面向切面编程, 韩老大 的 blog - PHP-AOP扩展介绍 | rango 可以看看.
需不需要了解一个新事物, 先看看这个事物有什么作用:
AOP, 将业务代码和业务无关的代码进行分离, 场景有 日志记录 / 性能统计 / 安全控制 / 事务处理 / 异常处理 / 缓存 等等.
这里引用一段 程序员DD - 翟永超的公众号 文章里的代码, 让大家感受下:
同样是 CRUD, 不使用 AOP
@PostMapping("/delete") public Map<String, Object> delete(long id, String lang) { Map<String, Object> data = new HashMap<String, Object>(); boolean result = false; try { // 语言(中英文提示不同) Locale local = "zh".equalsIgnoreCase(lang) ? Locale.CHINESE : Locale.ENGLISH; result = configService.delete(id, local); data.put("code", 0); } catch (CheckException e) { // 参数等校验出错,这类异常属于已知异常,不需要打印堆栈,返回码为-1 data.put("code", -1); data.put("msg", e.getMessage()); } catch (Exception e) { // 其他未知异常,需要打印堆栈分析用,返回码为99 log.error(e); data.put("code", 99); data.put("msg", e.toString()); } data.put("result", result); return data; }
使用 AOP
@PostMapping("/delete") public ResultBean<Boolean> delete(long id) { return new ResultBean<Boolean>(configService.delete(id)); }
代码只用一行, 需要的特性一个没少, 你是不是也想写这样的 CRUD 代码?
配置文件管理
先明确一下配置管理的痛点:
是否支撑热更新, 常驻内存需要考虑
考虑不同环境: dev test production
方便使用
热更其实可以算是常驻内存服务器的整体需求, 目前 php 常用的解决方案是 inotify, 可以参考我之前的 blog - swoft 源码解读 .
msf 使用第三方库来解析处理配置文件, 这里着重提一个 array_merge() 的细节:
$a = ['a' => [ 'a1' => 'a1', ]]; $b = ['a' => [ 'b1' => 'b1', ]]; $arr = array_merge($a, $b); // 注意, array_merge() 并不会循环合并 var_dump($arr); // 结果 array(1) { ["a"]=> array(1) { ["b1"]=> string(2) "b1" } }
msf 中使用配置:
$ids = $this->getConfig()->get('params.mock_ids', []); // 对比一下 laravel $ids = cofnig('params.mock_ids', []);
看起来 laravel 中要简单一些, 其实是通过 composer autoload 来加载函数, 这个函数对实际的操作包装了一层. 至于要不要这样做, 就看自己需求了.
写在最后
msf 最复杂的部分在 服务启动阶段, 继承也很长:
Child -> Server -> HttpServer -> MSFServer -> AppServer, 有兴趣可以挑战一下.
另外一个比较难的点, 是 MongoDbTask 实现原理.
msf 还封装了很多有用的功能, RPC / 消息队列 / restful, 大家根据文档自己探索即可.
本文共计1816个文字,预计阅读时间需要8分钟。
我们来看一下分享的伪原创内容:
原文:我们来分享一下整体源码:php-msf:https://github.com/pinguo/php-msf 源码解读也做了一段时期了,总结一下自己的心得:抓住生命周期,让代码在你的脑海中跑起来,分析架构,关键字,分层,边界
伪原创:分享整体源码资源:php-msf,链接为:https://github.com/pinguo/php-msf。对其源码进行解读已有段时间,个人感悟如下:紧握生命周期,使代码在心中活跃,深入分析架构、关键词、分层及边界。
我们来看分享下具体源码:php-msf:github.com/pinguo/php-msf
源码解读也做了一段时间了, 总结一下自己的心得:
抓住 生命周期, 让代码在你脑海中 跑起来
分析架构, 关键字 分层 边界 隔离
一个好的框架, 弄清楚 生命周期 和 架构, 基本就已经到了 熟悉 的状态了, 之后是填充细节和编码熟练了
这里再介绍几个次重要的心得:
弄明白这个工具擅长干什么, 适合干什么. 这个信息也非常容易获取到, 工具的文档通常都会显眼标注出来, 可以通过这些 功能/特性, 尝试以点见面
从工程化的角度去看这个项目, 主要和上面的 架构 区分, 在处理核心业务, 也就是上面的 功能/特性 外, 工程化还涉及到 安全/测试/编码规范/语言特性 等方面, 这些也是平时在写业务代码时思考较少并且实践较少的部分
工具的使用, 推荐我现在使用的组合: phpstorm + 百度脑图 + Markdown笔记 + blog和 php-msf 的渊源等写技术生活相关的 blog 再来和大家八, 直接上菜.
生命周期 & 架构
官方文档制作了一张非常好的图: 处理请求流程图. 推荐各位同仁, 有闲暇时制作类似的图, 对思维很有的帮助.
根据这张图来思考 生命周期 & 架构, 这里就不赘述了, 这里分析一下 msf 中一些技术点:
协程相关知识
msf 中技术点摘录
协程
我会用我的方式来讲解, 如果需要深入了解的, 可以看我后面推荐的资源.
类 vs 对象 是一组很重要的概念. 类代表我们对事物的抽象, 这个抽象的能力在我们以后会一直用到, 希望大家有意识的培养这方面的意识, 至少可以起到触类旁通的作用. 对象是 实例化 的类, 是 真正干活的, 我们要讨论的 协程, 就是这样一个 真正干活的 角色.
协程从哪里来, 到哪里去, 它是干什么的?
想一想这几个简单的问题, 也许你对协程的理解就更深刻了, 记住这几个关键词:
产生. 需要有地方来产生协程, 你可能不需要知道细节, 但是需要知道什么时候发生了
调度. 肯定是有很多协程一起工作的, 所以需要调度, 怎么调度的呢?
销毁. 是否会销毁? 什么时候销毁?
现在, 我们再来看看协程的使用方式对比, 这里注意一下, 我没有用 协程的实现方式对比, 因为很多时候, 需求实际是这样的:
怎么实现我不管, 我选最好用的.
// msf - 单次协程调度 $response = yield $this->getRedisPool('tw')->get('apiCacheForABCoroutine'); // msf - 并发协程调用 $client1 = $this->getObject(Client::class, ['www.baidu.com/']); yield $client1->goDnsLookup(); $client2 = $this->getObject(Client::class, ['www.qq.com/']); yield $client2->goDnsLookup(); $result[] = yield $client1->goGet('/'); $result[] = yield $client2->goGet('/');
大致 是这样的一个等式: 使用协程 = 加上 yield, 所以搞清楚哪些地方需要加上 yield 就好了 -- 有阻塞IO的地方, 比如 文件IO, 网络IO(redis/mysql/pecl.php.net/package/aop
PHP-AOP扩展介绍 | rango: rango.swoole.com/archives/83
AOP, 面向切面编程, 韩老大 的 blog - PHP-AOP扩展介绍 | rango 可以看看.
需不需要了解一个新事物, 先看看这个事物有什么作用:
AOP, 将业务代码和业务无关的代码进行分离, 场景有 日志记录 / 性能统计 / 安全控制 / 事务处理 / 异常处理 / 缓存 等等.
这里引用一段 程序员DD - 翟永超的公众号 文章里的代码, 让大家感受下:
同样是 CRUD, 不使用 AOP
@PostMapping("/delete") public Map<String, Object> delete(long id, String lang) { Map<String, Object> data = new HashMap<String, Object>(); boolean result = false; try { // 语言(中英文提示不同) Locale local = "zh".equalsIgnoreCase(lang) ? Locale.CHINESE : Locale.ENGLISH; result = configService.delete(id, local); data.put("code", 0); } catch (CheckException e) { // 参数等校验出错,这类异常属于已知异常,不需要打印堆栈,返回码为-1 data.put("code", -1); data.put("msg", e.getMessage()); } catch (Exception e) { // 其他未知异常,需要打印堆栈分析用,返回码为99 log.error(e); data.put("code", 99); data.put("msg", e.toString()); } data.put("result", result); return data; }
使用 AOP
@PostMapping("/delete") public ResultBean<Boolean> delete(long id) { return new ResultBean<Boolean>(configService.delete(id)); }
代码只用一行, 需要的特性一个没少, 你是不是也想写这样的 CRUD 代码?
配置文件管理
先明确一下配置管理的痛点:
是否支撑热更新, 常驻内存需要考虑
考虑不同环境: dev test production
方便使用
热更其实可以算是常驻内存服务器的整体需求, 目前 php 常用的解决方案是 inotify, 可以参考我之前的 blog - swoft 源码解读 .
msf 使用第三方库来解析处理配置文件, 这里着重提一个 array_merge() 的细节:
$a = ['a' => [ 'a1' => 'a1', ]]; $b = ['a' => [ 'b1' => 'b1', ]]; $arr = array_merge($a, $b); // 注意, array_merge() 并不会循环合并 var_dump($arr); // 结果 array(1) { ["a"]=> array(1) { ["b1"]=> string(2) "b1" } }
msf 中使用配置:
$ids = $this->getConfig()->get('params.mock_ids', []); // 对比一下 laravel $ids = cofnig('params.mock_ids', []);
看起来 laravel 中要简单一些, 其实是通过 composer autoload 来加载函数, 这个函数对实际的操作包装了一层. 至于要不要这样做, 就看自己需求了.
写在最后
msf 最复杂的部分在 服务启动阶段, 继承也很长:
Child -> Server -> HttpServer -> MSFServer -> AppServer, 有兴趣可以挑战一下.
另外一个比较难的点, 是 MongoDbTask 实现原理.
msf 还封装了很多有用的功能, RPC / 消息队列 / restful, 大家根据文档自己探索即可.

