时间:2017-10-10
php-msf版本:3.0.3
php版本:php7.1.8
vagrant版本:1.8.6
VM VirtualBox版本:5.1.8
操作系统;Win7_64bit
基于PHP-MSF DEMO项目.
介于官方文档中,常见问题信息太少,故在此做下记录.
目录结构
├── app // PHP业务代码
│ ├── AppServer.php // 应用server类,可根据需求自定义
│ ├── Controllers // 控制器类目录
│ ├── Lib // 特殊逻辑处理类目录
│ ├── Models // Model类目录
| ├ ├── Handlers目录 对外提供Rpc服务
| ├ ├── DTO目录 mysql table 对应的Model类
| ├ ├── DAO目录 mysql CRUD操作类 及 缓存处理.
│ ├── Route // 特殊路由规则类目录
│ ├── Tasks // Task类目录
│ └── Views // 视图文件目录
│ └── Services //业务逻辑处理类
├── build.sh // 构建脚本(拉取docker镜像,启动容器)
├── checkstyle.sh // 代码检查脚本
├── composer.json // composer包依赖配置文件
├── config // 配置目录
├── server.php // server启动脚本
├── console.php // 命令行脚本
├── test // 单元测试目录
MVC调用顺序为
Http请求:
Controller ---> Services ---> Dao ---> DTO
|
|
Views
Rpc请求: 注意rpc.php配置
Handlers(Controller) ---> Services ---> Dao ---> DTO
遇到的问题记录
1.规范:config目录不能存放除配置信息以外的其他内容,
比如一个php函数,如果有解析配置文件的函数,请放到Lib目录. 每个配置文件的最后都要return $config;
2.规范: Rpc的Handlers只能创建在models目录下.
不一定非得是models目录,但无规矩不成方圆,很容易被用乱了.
3.Rpc的高可用及负载均衡(词挺高大上,希望你明白是啥意思.)
有一个配置文件 rpc.php 内容为:
$config['service']['demo']['host'] = 'http://192.168.33.22:8000';
$config['service']['demo']['timeout'] = 2000;
$this->getObject(RpcClient::class, ['demo'])->handler('sum')->func('multi', 1, 2, 3, 4, 5);
详情在Controller目录里的RpcTest.php文件中.
那么,现在问题来了,demo服务,部署在多台机器上, 提供同样的功能,
是在rpc.php文件里配置多个吗?还是?
建议的做法为
$config['service']['demo']['host'] = 域名+端口.
然后使用阿里云SLB在域名解析上做负载均衡. 同类产品也可以.
或者,使用Nginx进行请求转发,然后做负载均衡,Nginx不一定非要和php-fpm合作,可以把请求转发到任意端口.
4.使用vagrant进行本地调试.代码变更之后worker没有自动reload
使用这个命令,运行就可以啦.
nodemon是node的解决方法. 记得一定要加上-L的参数,否则也是不好使的.
nodemon -L --exec php server.php
效果请看下图
或者使用
从php-msf官方人员得到,并为在vagrant中进行使用测试,推荐大家使用Docker.
公网地址: docker pull registry.cn-hangzhou.aliyuncs.com/pinguo-ops/php-msf-docker:latest
5.使用tail 命令查看日志文件时,不能使用jq小工具,以json格式方式查看日志. 日志内容看起来比较乱.
建议重写日志内容组成部分的代码. monlog
6.关于yield关键字.
Controller ---> Services ---> Dao ---> Model时.
如果Model层操作mysql时,使用了
$list =yield $this->getMysqlPool('master')->go(null, 'select * from biz');
那么,在Controller ---> Services ---> Dao是,都必须加上yield关键字,yield是需要层层嵌套的,否则程序异常.
但没有任何错误日志输出.
另外,当同一个类中A函数调用B函数时,如果B函数内部使用了yield关键字,那么A函数调用B函数时,也要使用yield关键字,否则程序异常.
但依然没有任何错误日志输出.
7.编辑器phpStorm代码跳转失效.
原因是
$dao = $this->getObject(MerchantDao::class);
$list = yield $dao->getAllMerchant();
修改成下面这样,就可以了.
/**
* @var MerchantDao $dao
*/
$dao = $this->getObject(MerchantDao::class);
$list = yield $dao->getAllMerchant();
请使用
phpStorm2017版本, 如果低于这个版本,即使添加了@var注释,当使用yield关键字时,依然无法跳转.
8.如何修改View视图文件的后缀名? 默认为.php
继承Controller类,重写outputView()函数.
/**
* 通过模板引擎响应输出HTML
*
* @param array $data 待渲染KV数据
* @param string|null $view 文件名
* @throws \Exception
* @throws \Throwable
* @throws Exception
* @return void
*/
public function outputView(array $data, $view = null)
{
if ($this->requestType !== Marco::HTTP_REQUEST) {
throw new \Exception('$this->outputView not support '. $this->requestType);
}
$this->getContext()->getOutput()->setContentType('text/html; charset=UTF-8');
if (empty($view)) {
$view = str_replace('\\', '/', $this->getContext()->getControllerName()) . '/' .
str_replace($this->getConfig()->get('http.method_prefix', 'action'), '', $this->getContext()->getActionName());
}
try {
$viewFile = ROOT_PATH . '/app/Views/' . $view;
$engine = getInstance()->templateEngine;
//设置视图模版文件后缀格式
$engine->setFileExtension('phtml');
$template = $engine->make($viewFile);
$response = $template->render($data);
} catch (\Throwable $e) {
$template = null;
/**
* 首先加载的视图文件为app/Views/Controller/Action.phtml,
* 如果失败,会继续加载php-msf/src/Views/Controller/Action.phtml,如果还是失败,则会抛出异常。
*/
$viewFile = getInstance()->MSFSrcDir . '/Views/' . $view;
try {
$engine = getInstance()->templateEngine;
//设置视图模版文件后缀格式
$engine->setFileExtension('phtml');
$template = $engine->make($viewFile);
$response = $template->render($data);
} catch (\Throwable $e) {
throw new Exception('app view and server view both not exist, please check again');
}
}
$template = null;
$this->getContext()->getOutput()->end($response);
}
说明:本人第一次使用php-msf,对部分概念不是很清晰,上面若有写的不对的地方,请在评论中进行交流, 灰常感谢.