加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程 > 正文

php-msf源码详解

发布时间:2021-04-02 12:31:19 所属栏目:编程 来源:网络整理
导读:我们来看分享下具体源码: 源码解读也做了一段时间了,总结一下自己的心得: 抓住 生命周期,让代码在你脑海中 跑起来 分析架构,关键字 分层 边界 隔离 一个好的框架,弄清楚 生命周期 和 架构,基本就已经到了 熟悉 的状态了,之后是填充细节和编码熟练了 这里再

swoole 本身是实现了隔离的:

on('request',$response) { $response->end("

Hello Swoole. #".rand(1000,9999)."

"); }); $http->start();

msf 在 Context 上还做了一层封装,让 Context 看起来 为所欲为:

getContext()->xxxModule->xxxModuleFunction();

细节可以查看 src/Helpers/Context.php 文件

对象池

对象池这个概念,大家可能比较陌生,目的是减少对象的频繁创建与销毁,以此来提升性能,msf 做了很好的封装,使用很简单:

getObject(DemoModel::class,[1,2]);

对象池的具体代码在 src/Base/Pool.php 下:

底层使用反射来实现对象的动态创建

if (!$poolName) {
return null;
}

$pool = $this->map[$poolName] ?? null;
if ($pool == null) {
$pool = $this->applyNewPool($poolName);
}

if ($pool->count()) {
$obj = $pool->shift();
$obj->__isConstruct = false;
return $obj;
} else {
// 使用反射
$reflector = new ReflectionClass($poolName);
$obj = $reflector->newInstanceWithoutConstructor();

$obj->__useCount  = 0;
$obj->__genTime  = time();
$obj->__isConstruct = false;
$obj->__DSLevel  = Macro::DS_PUBLIC;
unset($reflector);
return $obj;

}
}

使用 SplStack 来管理对象

map)) { throw new Exception('the name is exists in pool map'); } $this->map[$poolName] = new SplStack();

return $this->map[$poolName];
}
// 管理对象
$pool->push($classInstance);
$obj = $pool->shift();

连接池 & 代理

连接池 Pools

连接池的概念就不赘述了,我们来直接看 msf 中的实现,代码在 src/Pools/AsynPool.php 下:

callBacks = []; $this->commands = new SplQueue(); $this->pool = new SplQueue(); $this->config = $config; }

这里使用的 SplQueue 来管理连接和需要执行的命令. 可以和上面对比一下,想一想为什么一个使用 SplStack,一个使用 SplQueue.

代理 Proxy

代理是在连接池的基础上进一步的封装,msf 提供了 2 种封装方式:

主从 master slave

集群 cluster

查看示例 AppControllersRedis 中的代码:

getRedisPool('p1')->set('key1','val1'); $val = yield $this->getRedisPool('p1')->get('key1');
$this->outputJson($val);

}
// Redis代理使用示例(分布式)
public function actionProxySetGet()
{
for ($i = 0; $i <= 100; $i++) {
yield $this->getRedisProxy('cluster')->set('proxy' . $i,$i);
}
$val = yield $this->getRedisProxy('cluster')->get('proxy22');
$this->outputJson($val);
}

// Redis代理使用示例(主从)
public function actionMaserSlaveSetGet()
{
for ($i = 0; $i <= 100; $i++) {
yield $this->getRedisProxy('master_slave')->set('M' . $i,$i);
}

$val = yield $this->getRedisProxy('master_slave')->get('M66');
$this->outputJson($val);

}
}

代理就是在连接池的基础上进一步 搞事情. 以 主从 模式为例:

主从策略: 读主库,写从库 代理做的事情:

判断是读操作还是写操作,选择相应的库去执行 公共库

msf 推行 公共库 的做法,希望不同功能组件可以做到 可插拔,这一点可以看 laravel 框架和 symfony 框架,都由框架核心加一个个的 package 组成. 这种思想我是非常推荐的,但是仔细看 百度脑图 - php-msf 源码解读 这张图的话,就会发现类与类之间的依赖关系,分层/边界 做得并不好. 如果看过我之前的 blog - laravel源码解读 / blog - yii源码解读,进行对比就会感受很明显.

但是,这并不意味着 代码不好,至少功能正常的代码,几乎都能算是好代码. 从功能之外建立的 优越感,更多的是对 美好生活的向往 -- 还可以更好一点.

AOP

php AOP 扩展: http://pecl.php.net/package/aop

PHP-AOP扩展介绍 | rango: http://rango.swoole.com/archives/83

AOP,面向切面编程,韩老大 的 blog - PHP-AOP扩展介绍 | rango 可以看看.

需不需要了解一个新事物,先看看这个事物有什么作用:

AOP,将业务代码和业务无关的代码进行分离,场景有 日志记录 / 性能统计 / 安全控制 / 事务处理 / 异常处理 / 缓存 等等. 这里引用一段 程序员DD - 翟永超的公众号 文章里的代码,让大家感受下:

同样是 CRUD,不使用 AOP

delete(long id,String lang) { Map data = new HashMap(); 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

delete(long id) { return new ResultBean(configService.delete(id)); }

代码只用一行,需要的特性一个没少,你是不是也想写这样的 CRUD 代码?

配置文件管理

先明确一下配置管理的痛点:

是否支撑热更新,常驻内存需要考虑

考虑不同环境: dev test production

方便使用

热更其实可以算是常驻内存服务器的整体需求,目前 php 常用的解决方案是 inotify,可以参考我之前的 blog - swoft 源码解读 .

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读