PHP7.反射不适用于旧版本的PHP

Pau*_*hev 0 reflection php-7

我有一个php脚本,写在php 5.6.19上,适用于5.3版本,有一些已安装的插件.

我决定尝试在php7上执行它.

通过创建新实例,我通过引用初始化类的脚本的特殊性Reflection::class.然后有警告等待参考变量但收到的价值.

尝试从以下位置创建实例的类'构造函数方法的定义:

public function __construct($user, IDatabase &$repository, $errors = null);
Run Code Online (Sandbox Code Playgroud)

使用此构造函数的代码示例:

// define manager type to create (all managers has the same constructor)
$manager = $managersNamespace . ucfirst($this->_manager) . "Manager";
// trying to create the manager
// !!!And here a Warning occurs
$reflect = new \ReflectionClass($manager);
$manager = $reflect->newInstance($user, $database, $errors);
Run Code Online (Sandbox Code Playgroud)

在这些之后我调用了一个我需要的方法,这里停止了脚本的致命错误:

$method = "show" . ucfirst($this->_page) . "Page";
$reflect->getMethod($method)->invoke($manager);
Run Code Online (Sandbox Code Playgroud)

我没有看到文档有任何变化.有人有同样的问题吗?

Joe*_*ins 6

首先,为什么要通过引用传递对象!

对象具有pass-by-reference语义,强制尝试通过引用传递对象自PHP 4以来没有很好的意义.

只需删除&...

让我们忽略它,并假装仍然存在问题,以便您可以尝试了解发生了什么.

要解决问题,首先需要了解变量和表达式之间的区别:

mine(1 + 2);
Run Code Online (Sandbox Code Playgroud)

我的参数没有名称,它由引擎中的临时变量表​​示:它是一个表达式.

mine(1);
Run Code Online (Sandbox Code Playgroud)

我的参数没有名称,它不是表达式,而是一个文字常量,由引擎中的编译器变量表示.它类似于临时变量,一种常量表达式.

mine($a);
Run Code Online (Sandbox Code Playgroud)

我的参数有一个名称,您可以用它来引用它的值.这是一个正常的变量.

只能通过引用传递变量,因为您不能引用表达式或文字常量

接下来,您需要了解我们为什么通过引用传递:

function mine(int $thing) {
    $thing++;
}

$a = 1;

mine($a);

var_dump($a); // int(1)
Run Code Online (Sandbox Code Playgroud)

在这段代码中,$a传递给mine()由值,以便该变化mine()做出$thing只的范围内可见mine.$amine()返回调用之后没有变化,因为$a并且$thing是不同的,已经按值传递,这意味着它的值被复制到调用堆栈以进行调用mine().

function mine(int &$thing) {
    $thing++;
}

$a = 1;

mine($a);

var_dump($a); // int(2)
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,通过引用$a传递mine(),这意味着$a并且$thing不再是不同的.这些变化mine()做出$thing的调用后,现在可见mine()的回报.

拼图的最后一块是反思:

function mine(int &$thing) {
    $thing++;
}

$a = 1;

$reflector = new ReflectionFunction("mine");
$reflector->invoke($a);
Run Code Online (Sandbox Code Playgroud)

上面的代码将引发:

Warning: Parameter 1 to mine() expected to be a reference, value given in /usr/src/php-src/refs.php on line 9
Run Code Online (Sandbox Code Playgroud)

这是因为ReflectionFunction::invoke类似的反射函数(ReflectionClass::newInstance)按值接受它们的参数,通过将它们传递给调用的函数.

但......

传递引用语义和传递引用之间仍然存在差异,这是一个危险的:

class Foo {
    public function qux() {}
}

class Bar {}

function mine(Foo &$foo) {
  $foo = new Bar();        
}

$foo = new Foo;

mine($foo);

$foo->qux();
Run Code Online (Sandbox Code Playgroud)

显然会产生:

PHP Fatal error:  Uncaught Error: Call to undefined method Bar::qux() in /usr/src/php-src/refs.php:16
Stack trace:
#0 {main}
  thrown in /usr/src/php-src/refs.php on line 16
Run Code Online (Sandbox Code Playgroud)

mine()告诉声明取决于它的参数的类型安全性.只有在进入函数时才能保证类型安全,函数体可以自由地破坏类型安全性,但是当依赖引擎传递对象的引用语义时它通常不会影响调用者.

这是一种非常可怕的API,应该避免使用.