本周有空自己写了一个简单的redis队列,暂时能够运行起来。目的是为了更加深入理解redis和原生的php,抛开框架看看自己是什么程度,涉及到的内容有socket,redis的传输协议RESP,php错误异常处理,类的自动加载。
类的自动加载
框架里经常使用use 某个类,以为use就是引入相关的类文件,其实不是的,要引入文件还是要require或者include文件,但是每次引入类就要require,数量多了或者目录改变了,改起来就比较麻烦。于是找到自动加载的魔术方法__autoload();
use Xiaocheng\test\Test;
$class = new Test();
function __autoload($class){
//$class = 'Xiaocheng\test\Test'; use的作用, 不用use的话就是 Test;
$path = str_replace(['\\', NAMESPACE_PRE], ['/', ROOT_PATH], $class);//根据$class找出该类的文件的绝对路径
$file = $path.EXT;
if (is_file($file)) {
require_once $file;
}
}
根据命名空间和类就能找到该文件的绝对路径,然后引入(关于文件的命名如果要规范点的话要参考PSR)。这样类就是按需加载,并且不用每次都要require,如果是php内部的类就要用 \Exception;这就是为什么try{}catch(Exception $ex){}里一直没执行到的原因,不加 \ 一直用的是tp里自定义的类。
错误异常处理
在php中错误跟异常是不同的概念,这个就没必要细究了,框架里用的是自己处理异常的函数,set_error_handler,set_exception_handler都可以自定义处理错误异常的函数,error_reporting则是报告的错误级别。目前线上的项目出错了,要打开调试才能看到错误的信息,这里我将错误信息都记录到日志里,方便查看错误信息。错误方法里还可以做下优化,例如处理释放资源,php会自动处理还是要人工处理的还有待研究。
Redis
之前写过一个redis类,里面大概是fsocket链接redis,然后直接fwrite("GET key"),对返回的数据+,-等也不太了解。这次深入了解后,优化了一下代码。redis基本的类型以及相关命令操作,传输协议,这些是基础;哨兵,集群,运维等暂时还没到这种地步,稍微了解了一下。
Redis类用到的魔术方法是__call($name, $arg);redis这么多命令就不需要每个都写一个方法了,fwrite的数据是根据RESP协议拼起来的,不再是自己拼写的。拼接的方法是参考项目中redis队列sprintf的做法,还有用到array_map()方法。map和reduce函数在很多编程语言里也有,应该是比较重要的函数。该类在处理返回数据的时候,也是只是对数据进行简单的处理。
Queue
这个类暂时做的就是 lpush和rpop列表里的数据,然后执行。这个类还可以做很多优化,开始或者终止进程,优先处理权重高的元素等,fork子进程处理(php多进程);目前正在做抢购秒杀的问题,考虑是先在队列里设置好个数,由于redis是单进程的,rpop也是一个一个执行的,不会出现超个数的情况。接之后就是要解决如何模拟高并发请求来测试抢购秒杀的问题。
总结
这次redis队列的代码,虽然还很粗糙,但是重要的是从中更加深入地了解php这门语言以及意识到不能总是依赖框架或者某一个语言,C的基础也差不多学完了,接下来可以考虑php扩展C写的redis,之前就是止步于C的socket,比封装好的socket要复杂多了。不太愿意接触c的原因也是因为写c要懂得更多计算机方面的知识,内存管理,栈,堆等的,现在要提高自己水平的话就要去了解这些知识了。