使用迭代器打包phar
当你的项目符合单点入口,即所有请求都以index.php作为入口时,可以考虑使用phar打包代码。可能会方便线上部署,就跟java的jar一样。虽然现在很少看到有人这么做了,不过可以学习一下。
打包phar的核心类是Phar
类,网上的例子大多数是这样的:
//前略 file name:build.php
$file = "test.phar";
$phar = new Phar(__DIR__.'/'.$file, FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::KEY_AS_FILENAME, $file);
//开始打包
$phar->startBuffering();
//添加进去
$phar->buildFromDirectory(__DIR__, '/\.php$/');
$phar->buildFromDirectory(__DIR__, '/\.tpl$/');
//删除本身
$phar->delete('build.php');
//设置入口
$phar->setStub("<?php
Phar::mapPhar('{$file}');
require 'phar://{$file}/index.php';
__HALT_COMPILER();
?>");
然后使用php build.php
就可以打包成指定的phar文件。使用时可以php test.phar
即可。也可以require "test.phar";
需要注意的是,项目内部使用的php文件互相引用,最好使用绝对路径__DIR__
的方式。
这种方法使用指定目录文件的方式加载,可能不够灵活。这里提供一种使用目录迭代器的方式打包phar,省去了手动指定目录的步骤。
//先检查php.ini的配置 是否允许打包phar
if(ini_get('phar.readonly')==='1') {
throw new Exception('Please set phar.readonly to Off');
}
//检查运行环境是否是命令行
if(php_sapi_name()==='cli'){
$file = basename(__DIR__).'.phar';
new build($file, __DIR__);
}
//继承Phar类
class build extends Phar
{
function __construct($file, $source_dir)
{
if(is_file($file)) {
unlink($file);
}
parent::__construct($file);
//新建目录迭代器用来递归的遍历目录文件
$folder = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source_dir));
$items = [];
foreach($folder as $item) {
//排除掉不需要的文件和目录
if(strpos($item->getPathName(), '/.git/')) {
continue;
}
if(strpos($item->getPathName(), '.psd')) {
continue;
}
if(strpos($item->getPathName(), '/test/')) {
continue;
}
$filename = pathinfo($item->getPathName(), PATHINFO_BASENAME);
if(substr($filename, 0, 1) != '.') {
$items[substr($item->getPathName(), strlen($source_dir))] = $item->getPathName();
}
}
$this->startBuffering();
//使用buildFromIterator方法 而不是buildFromDirectory
$this->buildFromIterator(new ArrayIterator($items));
//删除本身
$this->delete('build.php');
$this->setStub("<?php
if(is_file('phar://'.__FILE__.'/index.php')) {
require 'phar://'.__FILE__.'/index.php';
}
__HALT_COMPILER();
?>");
$this->stopBuffering();
}
}