如何让含PHP 8.0 readonly关键字的库兼容PHP 7.4?
兼容PHP 7.4与readonly关键字的实用方案
一、用Composer脚本做批量代码预处理
这是最贴近你想要的C语言宏替换效果的方案,能在打包发布前自动处理所有文件:
- 写个预处理脚本
在项目里新建scripts/process_readonly.php,功能是遍历src下的所有PHP文件,把readonly关键字删掉:
<?php $sourceDir = __DIR__ . '/../src'; // 递归遍历所有PHP文件 $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($sourceDir)); foreach ($iterator as $file) { if ($file->getExtension() !== 'php') continue; $content = file_get_contents($file->getPathname()); // 匹配行首的readonly关键字并替换为空 $processedContent = preg_replace('/^\s*readonly\s+/m', '', $content); file_put_contents($file->getPathname(), $processedContent); }
- 配置Composer自动执行
在composer.json里加个脚本,发布前跑一下就行:
{ "scripts": { "pre-dist": "php scripts/process_readonly.php" } }
发布时先执行composer run pre-dist,再打包,就能得到兼容PHP7.4的版本;本地开发时保留readonly,不影响PHP8的语法校验。
二、用错误屏蔽做临时过渡(不推荐生产用)
PHP7.4会把readonly当成属性的普通前缀,只会触发警告不会致命,你可以在库的入口文件加一段代码屏蔽相关警告:
if (version_compare(PHP_VERSION, '8.0', '<')) { // 屏蔽readonly带来的警告和废弃提示 error_reporting(error_reporting() & ~E_WARNING & ~E_DEPRECATED); }
但这种方法会顺带屏蔽其他有用的警告,只适合临时救急,不建议在生产环境用。
三、分版本分支维护
直接搞两个分支:
main分支:保留readonly,只适配PHP8+php7.4-compat分支:手动移除readonly,适配PHP7.4
然后在composer.json里设置版本条件,让Composer自动给用户装对应版本:
{ "require": { "php": "^7.4 || ^8.0" } }
发布时分别打包两个分支的版本,用户安装时Composer会根据自己的PHP版本自动选对应的包。
四、用代码规范工具批量处理
用php-cs-fixer自定义规则批量删readonly:
- 先装依赖:
composer require --dev friendsofphp/php-cs-fixer - 新建
.php-cs-fixer.dist.php配置文件:
<?php $finder = PhpCsFixer\Finder::create() ->in(__DIR__ . '/src'); return (new PhpCsFixer\Config()) ->setRules([ // 自定义规则:移除属性前的readonly关键字 'remove_readonly' => function () { return new class implements PhpCsFixer\Fixer\FixerInterface { public function getDefinition() { return new PhpCsFixer\FixerDefinition\FixerDefinition( 'Removes readonly keyword for PHP 7.4 compatibility.', [] ); } public function isCandidate(\PhpCsFixer\Tokenizer\Tokens $tokens) { return $tokens->isTokenKindFound(T_STRING); } public function fix(\SplFileInfo $file, \PhpCsFixer\Tokenizer\Tokens $tokens) { for ($i = 0; $i < $tokens->count(); $i++) { if ($tokens[$i]->getContent() === 'readonly' && $tokens[$i+1]->isWhitespace()) { $tokens->clearAt($i); } } } public function getName() { return 'remove_readonly'; } public function getPriority() { return 0; } public function supports(\SplFileInfo $file) { return true; } }; }, ]) ->setFinder($finder);
- 执行命令批量处理:
php vendor/bin/php-cs-fixer fix
适合一次性生成兼容版本,之后可以把处理后的代码放到兼容分支里。
内容的提问来源于stack exchange,提问作者Sergey Slepov
相关产品推荐
相关产品推荐

