简略理解 Phar 代码打包工具的应用
Phar 是在 PHP5 之后提供的一种相似于将代码打包的工具。实质上是想按照 Java 的 Jar 文件那种模式的代码包,不过自身因为 PHP 是不编译的,所以这个 Phar 实际上就是将代码原样的进行打包,不会进行编译。然而咱们能够对打包的 Phar 包进行压缩操作。
另外,实际上应用过 Phar 包的人非常少,特地是在 Composer 曾经成为事实代码库规范的明天,Phar 就更加难觅踪影了。不过,Composer 的安装包自身也是一个 .phar 的打包文件。最次要的起因,一个是 Phar 这种模式的代码包装置并不像 Composer 一样的简略不便,另一方面,晚期的程序员,特地是 LAMP/LAMP 的程序员,都喜爱去将开源的代码复制过去,而不喜爱间接应用一个工具包。毕竟,源代码在手上让咱们更加虚浮一些。其实,就算是 Composer 这样间接下载的就是源码,咱们也素来没什么人真正的去翻过。而 Composer 相比 Phar 的最大劣势,一个是代码的主动加载,另一个就是规范的 PSR 命令空间和目录标准。这两个在 Phar 中是没有的,所以咱们要应用 Phar 包都必须要 require 一下。
虽说曾经过期了,但咱们还是简略的来学习理解一下。说不定在什么时候咱们就能用上,特地是封装一些外部的专用库函数时,Phar 打包代码的这种形式还是十分有用的。
代码打包
咱们先按规范格局建设一个目录树。
在这个目录树中,src 目录寄存源码,build 目录用来寄存生成后的 .phar 代码包。
// index.php
<?php
require_once "phar://myphar.phar/common.php";
index.php 文件中,咱们就是简略的援用 common.php。留神这里应用的是 phar 伪协定来加载的 common.php 文件。对于伪协定的内容咱们之前有过一篇文章进行过解说。
<?php
// common.php
class Manager{public static function run($config){
echo "AAA", PHP_EOL;
var_dump($config);
}
public static function ChineseMobile($mobile){if(preg_match("/^1[34578]\d{9}$/", $mobile)){return true;}
return false;
}
}
common.php 文件中只是提供了一个类和两个简略的办法用来测试。run() 办法就是简略的输入打印的内容和传递过去的参数。ChineseMobile() 办法则是咱们提供的一个判断咱们国内手机号的函数。
[database]
host=localhost
db=dbname
user=myuser
pass=dbpass
config.ini 是一个配置文件,其实咱们能够在 Phar 的代码中间接的进行配置文件的读取,也能够让配置文件随代码一起 build 到指定的目录。
源码文件筹备好了,接下来就是要筹备打包的编译文件了。
// create-phar.php
$srcRoot = "./myphar/src";
$buildRoot = "./myphar/build";
$phar = new Phar($buildRoot . "/myphar.phar",
FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::KEY_AS_FILENAME, "myphar.phar");
$phar["index.php"] = file_get_contents($srcRoot . "/index.php");
$phar["common.php"] = file_get_contents($srcRoot . "/common.php");
$phar->setStub($phar->createDefaultStub("index.php"));
copy($srcRoot . "/config.ini", $buildRoot . "/config.ini");
代码并不简单,次要是一个 Phar 类,这个类要指定生成文件的目录,文件名,而后应用 createDefaultStub() 办法来调用咱们包的入口文件 index.php,这个办法是用于创立指定的 .phar 文件的存根。其实就是指定一个入口文件,就像 Java 中的 main() 办法入口一样。
而后咱们拷贝了 config.ini 文件到公布目录 build 中。
接着应用命令行运行这个 create-phar.php 文件,就可能生成这套代码包了。
# php ./create-phar.php
应用文本编辑器关上 myphar.phar 文件,咱们会发现外面居然还是咱们相熟的 PHP 代码,拉到最底下,更会发现 index.php 和 common.php 的内容都被编译在这个文件中了。下面的那些主动生成的代码就是一些疏导或者前置筹备语句,是 Phar 扩大为咱们筹备好的内容,所有用户本人写的源码都会在这个文件的底部。也就是说,大家能够下载 Composer 的安装包,也就是那个 .phar 文件看看外面都写了什么货色。
接下来就是应用了,这个就非常简单了。
$config = parse_ini_file("./myphar/build/config.ini");
require './myphar/build/myphar.phar';
Manager::run($config);
// AAA
// array(4) {// ["host"]=>
// string(9) "localhost"
// ["db"]=>
// string(6) "dbname"
// ["user"]=>
// string(6) "myuser"
// ["pass"]=>
// string(6) "dbpass"
// }
var_dump(Manager::ChineseMobile('13811111111'));
var_dump(Manager::ChineseMobile('138111111112'));
// bool(true)
// bool(false)
压缩能力
后面说过,做为代码库来说,Phar 曾经早就败给了 Composer,然而它除了可能做为一些安装包来应用之外,自身 Phar 也是一个压缩工具。能够用来存档一些文件、文本、目录之类的内容。上面我就来简略看看对于文本的存档,Phar 是如何应用的。
unlink('./my.phar');
unlink('./my.phar.bz2');
unlink('./my.phar.gz');
$p = new Phar('./my.phar', 0 ,'my.phar');
$p['myfile1.txt'] = 'hi1';
$p['myfile2.txt'] = 'hi2';
$p1 = $p->compress(Phar::GZ);
$p2 = $p->compress(Phar::BZ2);
unset($p);
$decompressPhar = new Phar('./my.phar', 0 ,'my.phar');
foreach($decompressPhar as $file){
// $file 是返回的 PharFileInfo 对象
var_dump($file->getFileName());
var_dump($file->isCompressed());
var_dump($file->isCompressed(Phar::BZ2));
var_dump($file->isCompressed(Phar::GZ));
var_dump($file->getContent());
}
echo '==================', PHP_EOL;
// string(11) "myfile1.txt"
// bool(false)
// bool(false)
// bool(false)
// string(3) "hi1"
// string(11) "myfile2.txt"
// bool(false)
// bool(false)
// bool(false)
// string(3) "hi2"
首先,仍然是实例化一个 Phar 类,而后咱们给它像数组一样减少属性,这样,属性内容就被打包进了 .phar 文件中。通过间接查看 my.phar 文件,咱们能够看出,myfile1.txt 这两个属性间接被写成了文件进行保留了,也就是说,它帮咱们将文本转化成文件并打包在了 my.phar 这个压缩包文件中了。
compress() 办法则是将以后的这个 Phar 对象压缩存储为某个格局的文件。这里咱们间接压缩了 Bzip2 和 GZ 文件。调用这个办法后间接就会生成对应的压缩文件。
Phar 对象在遍历时产生的对象是 PharFileInfo 对象,它领有很多相似于 File 的文件操作函数。大家可能在官网文档中找到相干的阐明。
假如咱们遍历 my.phar.gz,内容仍然能够失常输入,但循环中的 isCompressed() 判断都仍然会是 false,难道文件没有被压缩吗?其实,咱们须要通过另一个函数来让所有文件都进行对立格局的压缩。
$p = new Phar('./my.phar', 0 ,'my.phar');
$p->compressFiles(Phar::GZ);
unset($p);
$decompressPhar = new Phar('./my.phar.gz', 0 ,'my.phar');
foreach($decompressPhar as $file){
// $file 是返回的 PharFileInfo 对象
var_dump($file->getFileName());
var_dump($file->isCompressed());
var_dump($file->isCompressed(Phar::BZ2));
var_dump($file->isCompressed(Phar::GZ));
var_dump($file->getContent());
}
echo '==================', PHP_EOL;
// string(11) "myfile1.txt"
// bool(true)
// bool(false)
// bool(true)
// string(3) "hi1"
// string(11) "myfile2.txt"
// bool(true)
// bool(false)
// bool(true)
// string(3) "hi2"
应用 compressFiles() 对整个 .phar 中的所有文件进行了对立的格局压缩之后,再打印时 isCompressed() 就会返回对应格局的 true 了。
数据格式 Phar
最初,如果只是为了打包压缩性能的话,咱们没必要应用 Phar 类。Phar 类最次要的还是用来打包可能运行的 PHP 源码,也就是它的 createDefaultStub() 办法十分重要。而如果只是打包一般文件的话,咱们并不需要这个办法,这时,咱们就能够应用另外一个 PharData 类来进行数据的打包压缩。应用办法和 Phar 类是截然不同的。同时,PharData 类能够间接打包成 tar 之类的文件。
$p = new PharData('./myData.tar');
$p['myfile1.txt'] = 'hi1';
$p['myfile2.txt'] = 'hi2';
foreach($p as $file){var_dump($file->getFileName());
var_dump($file->isCompressed());
var_dump($file->isCompressed(Phar::BZ2));
var_dump($file->isCompressed(Phar::GZ));
var_dump($file->getContent());
}
echo '==================', PHP_EOL;
// string(11) "myfile1.txt"
// bool(false)
// bool(false)
// bool(false)
// string(3) "hi1"
// string(11) "myfile2.txt"
// bool(false)
// bool(false)
// bool(false)
// string(3) "hi2"
总结
说实话,Phar 真的是一个冷门我的项目,然而在某些状况中又十分有用,比方它尽管在代码包畛域被 Composer 战胜了,然而它又能够成为 Composer 的安装包,也就是说,没有 Phar 你就装置不了 Composer。而做为压缩工具,尽管有弱小的实力但应用的却也十分的少。因而,咱们还是以理解为目标,如果感觉某些场景十分适合的话,也齐全能够深刻的钻研拿来放到咱们的理论我的项目中应用。毕竟它是 PHP 的一部分,不须要任何的编译装置及其它反对,十分原生。
测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202007/source/%E7%AE%80%E5%8D%95%E4%BA%86%E8%A7%A3Phar%E4%BB%A3%E7%A0%81%E6%89%93%E5%8C%85%E5%B7%A5%E5%85%B7%E7%9A%84%E4%BD%BF%E7%94%A8.php
参考文档:
https://www.php.net/manual/zh/book.phar.php
https://www.webhek.com/post/packaging-your-php-apps-with-phar.html
http://www.mamicode.com/info-detail-888559.html
===========
各自媒体平台均可搜寻【硬核项目经理】