PHP 自动加载机制的实现

前言

现在很多php框架都使用了命名空间来实现autoloader自动加载机制,配合编辑器的自动use避免了平凡include文件,开发起来十分方便,之前自己尝试写框架时候也使用到了autoloader机制,这里特意记录下.

实现过程

php有个__autoload() 函数,实现了在加载一个文件失败后尝试调用__autoload() 函数进行最后一次加载,因此通过一个有规律的命名规则就可以实现简单的自动加载机制

<?php
//实现自动加载当前目录下以类名命名的所有文件
function __autoload($classname) {
    $filename = "./". $classname .".php";
    include_once($filename);
}
$obj = new myClass();
?>

这种方式的缺点也显而易见,__autoload() 只能注册一个,如果项目有引用其他模块并且也使用到了__autoload() 就有冲突了,这个时候就需要使用spl_autoload_register 来注册自己的autoload方法

升级版

<?php

/**
 * 自动载入
 * Class autoloader
 */
class autoloader
{

    private static $class_map = array();  //namespace => dir


    public function __construct()
    {
        spl_autoload_register('self::my_autoload');  //or spl_autoload_register(array('autoloader', 'my_autoload'));
    }

    private function my_autoload($class)
    {
        $filename = self::getfilename($class);
        include $filename;
    }

    //根据命名空间获得文件路径
    private static function getfilename($namespace)
    {
        $name_paths = explode('\\', $namespace);
        if (!isset(self::$class_map[$name_paths[0]])) {
            exit("`{$name_paths[0]}` 命名空间未注册,请使用addClassMap注册");
        } else {
            $filename = self::$class_map[$name_paths[0]] . '/';
            unset($name_paths[0]);
            $filename .= implode('/', $name_paths);
        }
        return $filename . '.php';
    }


    public static function addClassMap($namespace, $dir)
    {
        self::$class_map[$namespace] = $dir;
    }

    public static function getClassMap()
    {
        return self::$class_map;
    }
}

只需要在程序入口处引入此文件,就可以实现对其他文件的自动载入,如下

<?php
use Test\Image;

include 'autoloader.php';

$autoloader = new \autoloader();
$autoloader->addClassMap('Test', './Test');  //注册命名空间,路径是相当于当前目录,而不是autoloader.php

$a = new Image();

其中命名空间注册只需要对顶级目录进行注册后,就可以对所有子目录下的文件实现自动加载,namespace的命名规则必须与目录和文件的命名一一对应

如文件在Test目录下,那么namespace 为 Test,class为Image,那么使用时就是

use Test\Image; 
$image=  new Image();

或者

$image = new \Test\Image();

 

使用APIDOC自动生成api接口文档

安装nodejs和npm

Centos参考这个链接安装nodejs和npm

apidoc依赖node.js的npm管理工具,安装方法如下

sudo apt-get install nodejs
curl http://npmjs.org/install.sh | sudo sh

安装apidoc

sudo npm install apidoc -g

使用

<?php
class test{

/**
 * @api {get} /aaa/user 获取用户
 * @apiHeader {String} access-key Users unique access-key.
 * @apiName GetUser
 * @apiGroup User
 * 
 * @apiParam {Number} id 用户id

 * @apiSuccess {String} firstname Firstname of the User.
 * @apiSuccess {String} lastname  Lastname of the User.
 * @apiSuccessExample {json} Success-Response:
 *     HTTP/1.1 200 OK
 *     {
 *       "firstname": "John",
 *       "lastname": "Doe"
 *     }
 */
function user(){

}

}

apidoc.json

{
  "name": "api",
  "version": "0.1.0",
  "description": "这里是描述",
  "title": "这里是title",
  "url" : "这里是url"
}

 

生成命令

apidoc -i ./  -o apidoc/

生成的文档如下所示

QQ截图20151020143809

参考链接

PHP下Composer依赖包管理工具使用

简介

Composer是一个可以用来安装管理指定依赖包的工具

安装Composer

方法1

curl -sS https://getcomposer.org/installer | php

方法2

php -r "readfile('https://getcomposer.org/installer');" | php

使用

确保当前目录存在composer.json 依赖配置文件,例如

{
    "require": {
        "monolog/monolog": "1.2.*"
    }
}

其中,版本号可以使用>、>=、<、<=、!= ,或使用* 通配符

php composer.phar install

或者将composer.phar 复制到/usr/bin/composer ,执行composer install

安装完成后会自动创建composer.lock 锁文件,里面包含确切的版本号。下次执行install会下载相同的版本使环境保持一致。

如果如要更新依赖库的版本号,执行php composer.phar update ,将根据composer.json 文件配置更新依赖包,并重新生成composer.lock 锁文件

自动加载机制使用与配置

composer会自生成一个自动加载的支持,只需加入如下代码

require 'vendor/autoload.php';

也可以在composer.json的autoload字段添加自己的autoloader

{
    "autoload": {
        "psr-4": {"Acme\\": "src/"}
    }
}

Composer 将注册一个 PSR-4 autoloader 到 Acme 命名空间。

你可以定义一个从命名空间到目录的映射。此时 src 会在你项目的根目录,与 vendor 文件夹同级。例如 src/Foo.php 文件应该包含 Acme\Foo 类。

添加 autoload 字段后,你应该再次运行 install 命令来生成 vendor/autoload.php 文件。

引用这个文件也将返回 autoloader 的实例,你可以将包含调用的返回值存储在变量中,并添加更多的命名空间。这对于在一个测试套件中自动加载类文件是非常有用的,例如。

$loader = require 'vendor/autoload.php';
$loader->add('Acme\\Test\\', __DIR__);

除了 PSR-4 自动加载,classmap 也是支持的。这允许类被自动加载,即使不符合 PSR-0 规范。详细请查看 自动加载-参考

注意: Composer 提供了自己的 autoloader。如果你不想使用它,你可以仅仅引入 vendor/composer/autoload_*.php 文件,它返回一个关联数组,你可以通过这个关联数组配置自己的 autoloader。

配置使用更快的源

1,使用全局配置,执行如下命令

composer config -g repositories.packagist composer http://packagist.phpcomposer.com

2,在composer.json 追加如下配置,其中“packagist”: false 表示不使用Packagist ,Packagist 是 Composer 主要的一个包信息存储库,它默认是启用的

"repositories": [
        {"type": "composer", "url": "http://packagist.phpcomposer.com"},
        {"packagist": false}
]

composer.json配置文件说明

参考 库(资源包)

所有在 composer.json 中可用的字段

命令列表

 

Swoole 学习笔记

简介

Swoole是PHP语言的高性能网络通信框架,提供了PHP语言的异步多线程服务器,异步TCP/UDP网络客户端,异步MySQL,数据库连接池,AsyncTask,消息队列,毫秒定时器,异步文件读写,异步DNS查询。

安装Swoole

 

服务端实例代码(阻塞)

<?php


class Server
{
    private $serv;

    public function __construct()
    {
        $this->serv = new swoole_server("0.0.0.0", 9501);
        $this->serv->set(array(
            'worker_num' => 8,  //每个worker大概40M内存 cpu1~4倍最合理
            'daemonize' => false,  //是否守护进程后台执行
//            'log_file' => '/data/log/swoole.log',  //结果日志,守护运行时配置
            'debug_mode' => 1,
            'max_request' => 10000,  //设置worker进程的最大任务数
            'dispatch_mode' => 2,  //轮循模式,收到会轮循分配给每一个worker进程
            'task_worker_num' => 8,  //配置task进程的数量
            'task_max_request' => 10000  //设置task进程的最大任务数

        ));
        $this->serv->on('Start', array($this, 'onStart'));
        $this->serv->on('Connect', array($this, 'onConnect'));
        $this->serv->on('Receive', array($this, 'onReceive'));
        $this->serv->on('Close', array($this, 'onClose'));
        // bind callback
        $this->serv->on('Task', array($this, 'onTask'));
        $this->serv->on('Finish', array($this, 'onFinish'));
        $this->serv->start();
    }


    public function onStart($serv)
    {
        echo "Start\n";
    }

    public function onConnect($serv, $fd, $from_id)
    {
        echo "Client {$fd} connect\n";
    }

    public function onReceive(swoole_server $serv, $fd, $from_id, $data)
    {
        echo "Get Message From Client {$fd}:{$data}\n";
        // send a task to task worker.
        $param = array(
            'fd' => $fd
        );

        //调用task
        $serv->task(json_encode($param));


    }

    public function onClose($serv, $fd, $from_id)
    {
        echo "Client {$fd} close connection\n";
    }

    public function onTask($serv, $task_id, $from_id, $data)
    {

        echo "This Task {$task_id} from Worker {$from_id}\n";
        echo "Data: {$data}\n";
        for ($i = 0; $i < 10; $i++) {
            sleep(1);
            echo "Taks {$task_id} Handle {$i} times...\n";
        }
        $fd = json_decode($data, true)['fd'];
        $serv->send($fd, "Data in Task {$task_id}");
        return "Task {$task_id}'s result";
    }

    public function onFinish($serv, $task_id, $data)
    {
        echo "Task {$task_id} finish\n";
        echo "Result: {$data}\n";
    }
}

$server = new Server();

其中 $fd 为客户端链接id ,$from_id为 Worker产生的id  ,$task_id 为task id

客户端实例代码(阻塞式)

<?php

$client = new swoole_client(SWOOLE_SOCK_TCP);
if (!$client->connect('127.0.0.1', 9501, -1)) {
    exit("connect failed. Error: {$client->errCode}\n");
}
$client->send("hello world\n");
echo $client->recv();
$client->close();

 

使用注意

ulimit -n 要调整为100000甚至更大

# ulimit -n 1000000

 

 

参考资料

PHP分词工具,SCWS安装

简介

SCWS 是 Simple Chinese Word Segmentation 的首字母缩写(即:简易中文分词系统)。

这是一套基于词频词典的机械式中文分词引擎,它能将一整段的中文文本基本正确地切分成词

下载SCWS源码包

# wget http://www.xunsearch.com/scws/down/scws-1.2.2.tar.bz2
# tar jxvf scws-1.2.2.tar.bz2
# cd scws-1.2.2

编译安装

# ./configure --prefix=/wwjie/scws
# make && make install

安装词库

# wget http://www.xunsearch.com/scws/down/scws-dict-chs-gbk.tar.bz2
# wget http://www.xunsearch.com/scws/down/scws-dict-chs-utf8.tar.bz2
# tar xvjf scws-dict-chs-gbk.tar.bz2
# tar xvjf scws-dict-chs-utf8.tar.bz2

安装PHP扩展

# cd ./phpext
# phpize 
# ./configure --with-php-config=/usr/local/php5410/bin/php-config
# make && make install

编辑php.ini 添加如下内容

[scws]
;
; 注意请检查 php.ini 中的 extension_dir 的设定值是否正确, 否则请将 extension_dir 设为空,
; 再把 extension = scws.so 指定绝对路径。
extension = scws.so
scws.default.charset = utf8
scws.default.fpath = /wwjie/scws/etc

使用

<?php
$so = scws_new();
$so->set_charset('gbk');
// 这里没有调用 set_dict 和 set_rule 系统会自动试调用 ini 中指定路径下的词典和规则文件
$so->send_text("我是一个中国人,我会C++语言,我也有很多T恤衣服");
while ($tmp = $so->get_result())
{
  print_r($tmp);
}
$so->close();

 

PHP性能分析工具 XHProf 安装与使用

简介

xhprof是一个比xdebug更加强大的轻量级调试和性能分析工具 https://github.com/phacility/xhprof

安装配置

wget http://pecl.php.net/get/xhprof-0.9.4.tgz
tar zxvf xhprof-0.9.4.tgz
cd xhprof-0.9.4/extension/
sudo phpize
./configure --with-php-config=/usr/local/php/bin/php-config
sudo make && make install

或者 yum install php-xhprof

修改php.ini 新增:
extension = xhprof.so
; 注意:output_dir 必须存在且可写
xhprof.output_dir = /tmp/xhprof

使用

xhprof源码中的 xhprof_html 和 xhprof_lib两个文件夹将会使用到

xhprof_enable(XHPROF_FLAGS_NO_BUILTINS | XHPROF_FLAGS_CPU | XHPROF_FLAGS_MEMORY);  //开始

//todo 需要监控的代码  
// .....

$data = \xhprof_disable();   //返回运行数据
include_once 'xhprof_lib/utils/xhprof_lib.php';
include_once 'xhprof_lib/utils/xhprof_runs.php';
$objXhprofRun = new \XHProfRuns_Default();
$run_id = $objXhprofRun->save_run($data, "xhprof");
var_dump($run_id);

查看结果

拷贝  xhprof_html 和  xhprof_lib到一个可以访问的路径

访问 http://127.0.0.1/xhprof_html/index.php 即可看到结果

查看图形结果

# yum install libpng
# yum install graphviz

安装完成后 点击页面中的[View Full Callgraph] 即可看到图形结果

说明

输出结果
ct 函数调用次数,
wt 花费的时间,
cpu 花费的 CPU 时间(微秒即百万分之一秒),
mu 使用的内存(bytes),
pmu 使用的内存峰值(bytes)。

xhprof_enable 参数
XHPROF_FLAGS_CPU 分析结果中添加 CPU 数据
XHPROF_FLAGS_MEMORY 分析结果中添加内存数据
XHPROF_FLAGS_NO_BUILTINS 跳过 PHP 内置函数

结果说明
Incl. CPU (microsecs):包含内部函数 CPU 花费的时间,单位微秒
Excl. CPU (microsec):不包含内部函数 CPU 花费的时间,单位微秒
Incl. MemUse (bytes):包含内部函数所占内存,单位字节
Excl. MemUse (bytes):不包含内部函数所占内存,单位字节
Incl. PeakMemUse (bytes):包含内部函数所占内存峰值,单位字节
Excl. PeakMemUse (bytes):不包含内部函数所占内存峰值,单位字节及所占百分比(%)

Calls:函数的调用次数
Incl.:为 Including 包含的简写 
Excl.:为 Excluding 不包含的简写 
Wall Time:意为挂钟时间即任务花费的时间
main():一个虚构的函数,程序根节点 
bar@2:递归调用 2 次

可以认为共三种情况:
1. 包括内部函数
2. 不包括内部函数或者说函数本身
3. 所占总数(时间或内存使用)的百分比
peak 意为峰值

 

 

 

fedora19 yum 安装php5.5.1 nginx1.4.2 mysql

安装mysql

首先输入如下命令:
yum install mysql mysql-server
系统将自动完成mysql安装

如果不仅仅在本机访问数据库需要注释#skip-networking
vi /etc/my.cnf

将mysql加入开机启动,并启动mysql

systemctl enable mysqld.service
systemctl start mysqld.service

mysql安装完成!

安装nginx 与 php

yum install nginx php php-fpm
如果 没有nginx可以从http://nginx.org/en/linux_packages.html添加nginx源到yum

配置nginx.conf使nginx支持php,去掉如下代码的注释
nano /etc/nginx/nginx.conf

location ~ .php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME  /usr/share/nginx/html$fastcgi_script_name;
include fastcgi_params;
}

将nginx设为开机启动,启动nginx

systemctl enable nginx.service
systemctl start nginx.service

将php设为开机启动,启动php

systemctl enable php-fpm.service
systemctl start php-fpm.service

创建测试文件

info.php
<php
phpinfo();