asmblah/php-code-shift

v0.1.16 2024-09-11 06:42 UTC

README

Build Status

允许在预编译时或在运行时动态修改PHP代码。

为什么?

例如,为了在测试期间模拟内置函数。

使用方法

使用Composer安装此包

$ composer require asmblah/php-code-shift

挂钩内置函数

runner.php

<?php

use Asmblah\PhpCodeShift\CodeShift;
use Asmblah\PhpCodeShift\Shifter\Filter\FileFilter;
use Asmblah\PhpCodeShift\Shifter\Shift\Shift\FunctionHook\FunctionHookShiftSpec;

require_once __DIR__ . '/vendor/autoload.php';

$codeShift = new CodeShift();

$codeShift->shift(
    new FunctionHookShiftSpec(
        'substr',
        function (callable $originalSubstr) {
            return function (string $string, int $offset, ?int $length = null) use ($originalSubstr) {
                return '[substr<' . $originalSubstr($string, $offset, $length) . '>]';
            };
        }
    ),
    new FileFilter(__DIR__ . '/substr_test.php')
);

include __DIR__ . '/substr_test.php';

substr_test.php

<?php
// NB: substr(...) will be hooked by the shift defined inside runner.php.
$myResult = substr('my string', 1, 4) . ' and ' . substr('your string', 1, 2);

print $myResult;

输出将是

[substr<y st>] and [substr<ou>]

挂钩类

类的引用可以被替换成对其他类的引用。这仅适用于静态引用的类,即使用裸词进行引用的地方,例如 new MyClass

不支持动态/变量引用,例如 new $myClassName,因为它们只能在运行时解析。

任何匹配的类型都不会被替换 - 替换的类必须扩展原始类或接口,以便通过类型检查。

runner.php

<?php

use Asmblah\PhpCodeShift\CodeShift;
use Asmblah\PhpCodeShift\Shifter\Filter\FileFilter;
use Asmblah\PhpCodeShift\Shifter\Shift\Shift\ClassHook\ClassHookShiftSpec;

require_once __DIR__ . '/vendor/autoload.php';

$codeShift = new CodeShift();

$codeShift->shift(
    new ClassHookShiftSpec(
        'MyClass',
        'MyReplacementClass'
    ),
    new FileFilter(__DIR__ . '/class_test.php')
);

include __DIR__ . '/class_test.php';

class_test.php

<?php

class MyClass
{
    public function getIt(): string
    {
        return 'my original string';
    }
}

class MyReplacementClass
{
    public function getIt(): string
    {
        return 'my replacement string';
    }
}

// NB: References to MyClass will be hooked by the shift defined inside runner.php.
$myObject = new MyClass;

print $myObject->getIt();

输出将是

my replacement string

静态方法调用(MyClass::myStaticMethod())和类常量获取(MyClass:MY_CONST)也受支持。

限制

目前功能极其有限,您可能最好使用下面列出的替代方案之一。

  • 尚不支持 eval(...)
  • FunctionHookShiftType 尚不支持变量函数调用。
  • FunctionHookShiftType 尚不支持 call_user_func(...) 和类似函数,也不支持接受可能引用函数的可调用参数的任何其他函数。

另请参阅