背景:之前的文章里有写过用crontab+wget命令去请求项目代码的路径方式作为定时器,功能可以达到想要的。最近看到项目里的定时器的实现方式,却是不一样了,可以直接用php的cli模式访问对应的文件就可以了。感觉很简洁、可以和对外的http请求处理分离。另外如果在http的mvc模式的控制器层和数据模型层之间,添加上业务处理层BLL或者服务层service的话。那么,你就可以以最少的代码分离定时器层和对用户的http层了。
cli模式下的定时器访问类似于(配置在crontab里)
#通用统计:定时统计指定日期的各文章的赞数情况 cdy102688
30 5 * * * /usr/local/php/bin/php /data1/htdocs/www.aibaitou.com/timer/timer.php blog.getEveryDayTotalVotes >> /dev/null 2>&1
完整示例
*/1 * * * * /usr/local/php/bin/php /data1/htdocs/www.aibaitou.com/timer.php Hello.helloName tony 27
timer.php(完成定时器访问业务的转发)
<?php
if (PHP_SAPI == 'cli') {
$control = isset($argv[1]) ? $argv[1] : 'Hello.helloName';
$controlArr = explode(".", $control);
if (count($controlArr) != 2){
echo "参数不对";exit;
}
// 获取处理业务对应的类和方法
$class = $controlArr[0];
$method = $controlArr[1];
$includeFile = __DIR__.'/'.strtolower($class).".php";
// 加载处理业务文件
if (file_exists($includeFile)){
include_once $includeFile;
// 校验类和方法是否存在
$classSpace = "\\cdy\\hello\\".$class;
if (class_exists($classSpace) && method_exists($classSpace, $method)){
$classObj = new $classSpace;
// 获取函数需要用到的参数
$refServiceMethod = new ReflectionMethod($classObj, $method);
$args = array();
$paramCount = 0;
foreach ($refServiceMethod->getParameters() as $refParamObj) {
if (!isset($argv[($paramCount+2)])) {
if($refParamObj->isDefaultValueAvailable()){
$args[] = $refParamObj->getDefaultValue();
}else{
echo "类{$classSpace}函数{$method}参数 ".$refParamObj->getName()."缺少";exit;
}
}else{
$args[] = $argv[($paramCount+2)];
}
$paramCount ++;
}
call_user_func_array(array($classObj, $method), $args);
//call_user_func(array($classObj, $method), $argv[2], $argv[3]);
echo "\n<pre>";print_r($argv);exit;
}else{
echo "类{$classSpace}函数{$method}不存在";exit;
}
}else{
echo "文件{$includeFile}不存在";exit;
}
}else{
echo "执行模式错误";exit;
}
业务处理文件hello.php(文件名用类名小写)
<?php
namespace cdy\hello;
class Hello{
public function helloName($name, $age){
echo "hello {$name}!you are {$age}";
}
}
执行后输出:
hello tony!you are 27
<pre>Array
(
[0] => /data1/htdocs/www.aibaitou.com/timer.php
[1] => Hello.helloName
[2] => tony
[3] => 27
)
总结:
1.在php的cli模式下执行脚本时,有两个特殊的变量
a.$argv变量,它通过命令行把传递给PHP脚本的参数保存为单独的数组元素;如上第一个参数为访问的脚本文件地址,第二参数为处理业务类和方法,后面的参数为函数所需要的传入参数。
b.$argc变量,它用来保存$argv数组里元素的个数
2.类ReflectionMethod关于php自定义类的方法参数信息获取(如上面用到的获取参数名,是否有默认值等)
3.调用指定类方法call_user_func_array(array($classObj, $method), $args);应用