反序列化后的PHP文档评论

时间:2017-09-11 12:13:41

标签: php reflection

PHP中的ReflectionMethod实例(http://php.net/manual/en/class.reflectionmethod.php)具有getDocComment方法,该方法返回方法的注释。除非你使用反序列化的对象,否则这样做没问题。

$ref = new ReflectionClass('a');
var_dump(method_exists($ref, 'getDocComment')); //bool(true)
var_dump($ref->getDocComment()); //bool(false)

$ref = unserialize(serialize($ref));
var_dump(method_exists($ref, 'getDocComment')); //bool(true)
var_dump($ref->getDocComment()); //PHP Warning:  Uncaught Error: Internal error: Failed to retrieve the reflection object

有没有办法测试ReflectionMethod对象是否正确定义了文档注释?我的意思是,我不关心在序列化/反序列化后获取注释,但我想检查调用getDocComment是否安全。

编辑:根据建议错误处理+回退的回复,我改写了Q。

我有一些简单的反射缓存(ReflectionMethod个对象的数组)。直到我使用该缓存中的项目,我才想知道它的正确性。我不想处理错误,我想“预测错误”。令人敬畏的是hasDocComment方法,它不会产生任何错误,但在任何ReflectionMethod对象状态内只返回true / false。

2 个答案:

答案 0 :(得分:2)

序列化反射对象的一般方法是错误的。它有一个PHP Bug报告,但它被设置为"无关紧要":

https://bugs.php.net/bug.php?id=70719

原因是,您无法再将反射对象重新连接到其类,因为您必须处理源代码更改和各种内容。你应该做的是,序列化类的名称,并在反序列化时从该类生成一个新的反射对象。

代码示例:

class A { }
$ref = new ReflectionClass('A');
var_dump(method_exists($ref, 'getDocComment')); 

// serialize only the class name    
$refClass = unserialize(serialize($ref->getName()));

// get a new reflection object from that class ...
$ref = new ReflectionClass($refClass);
var_dump(method_exists($ref, 'getDocComment')); 

// If you want to serialize an object 
$a = new A();
$a2 = unserialize(serialize($a));
$ref = new ReflectionClass(get_class($a2));
var_dump(method_exists($ref, 'getDocComment'));

答案 1 :(得分:1)

如果您需要能够处理错误,可以尝试/捕获执行块。自alt-php71-7.1.0-1(您似乎正在使用)以来,这将抛出Error的实例,而不仅仅是Fatal Error,这样您就可以进行错误处理。

<?php
class A { }
$ref = new ReflectionClass('A');
var_dump(method_exists($ref, 'getDocComment')); //bool(true)
var_dump($ref->getDocComment()); //bool(false)

// serialize only the class name    
$refClass = unserialize(serialize($ref));
try {
    $refClass->getDocComment();
    // do your work
}
catch (Error $e) {
    echo "Malformed Reflection object: ".$e->getMessage();
}

Demo

由于您仍然可以从格式错误的Reflection实例中获取类名,因此您可以在catch块中实例化一个新的名称:

<?php
class A { }
$ref = new ReflectionClass('A');
var_dump(method_exists($ref, 'getDocComment')); //bool(true)
var_dump($ref->getDocComment()); //bool(false)

// serialize only the class name    
$refClass = unserialize(serialize($ref));
try {
    $refClass->getDocComment();
}
catch (Error $e) {
    $recoveredRef = new ReflectionClass($refClass->getName());
    var_dump($recoveredRef);
    var_dump($recoveredRef->getDocComment()); // works correctly
    echo "Malformed Reflection object, but recovered: ".$e->getMessage();
}

Demo