我在我的项目中使用PHP-分析器。我想用PHPUnit的assertEquals函数比较两个节点。
尽管节点是相同的,但它提供了一个错误的结果。原因是,其中一个节点包含两个受保护的属性,而另一个节点不包含:
["attributes":protected]=>
array(2) {
["startLine"]=>
int(2)
["endLine"]=>
int(2)
}可以比较排除受保护属性的节点吗?
示例数据
第一个目标是:
array(1) {
[0]=>
object(PhpParser\Node\Stmt\Expression)#5924 (2) {
["expr"]=>
object(PhpParser\Node\Expr\Assign)#5923 (3) {
["var"]=>
object(PhpParser\Node\Expr\Variable)#5918 (2) {
["name"]=>
string(1) "x"
["attributes":protected]=>
array(2) {
["startLine"]=>
int(2)
["endLine"]=>
int(2)
}
}
["expr"]=>
object(PhpParser\Node\Expr\ArrayDimFetch)#5922 (3) {
["var"]=>
object(PhpParser\Node\Expr\Variable)#5919 (2) {
["name"]=>
string(3) "arr"
["attributes":protected]=>
array(2) {
["startLine"]=>
int(2)
["endLine"]=>
int(2)
}
}
["dim"]=>
object(PhpParser\Node\Scalar\String_)#5934 (2) {
["value"]=>
string(3) "FOO"
["attributes":protected]=>
array(0) {
}
}
["attributes":protected]=>
array(2) {
["startLine"]=>
int(2)
["endLine"]=>
int(2)
}
}
["attributes":protected]=>
array(2) {
["startLine"]=>
int(2)
["endLine"]=>
int(2)
}
}
["attributes":protected]=>
array(2) {
["startLine"]=>
int(2)
["endLine"]=>
int(2)
}
}
}第二个目标是:
array(1) {
[0]=>
object(PhpParser\Node\Stmt\Expression)#5930 (2) {
["expr"]=>
object(PhpParser\Node\Expr\Assign)#5929 (3) {
["var"]=>
object(PhpParser\Node\Expr\Variable)#250 (2) {
["name"]=>
string(1) "x"
["attributes":protected]=>
array(2) {
["startLine"]=>
int(2)
["endLine"]=>
int(2)
}
}
["expr"]=>
object(PhpParser\Node\Expr\ArrayDimFetch)#5928 (3) {
["var"]=>
object(PhpParser\Node\Expr\Variable)#5926 (2) {
["name"]=>
string(3) "arr"
["attributes":protected]=>
array(2) {
["startLine"]=>
int(2)
["endLine"]=>
int(2)
}
}
["dim"]=>
object(PhpParser\Node\Scalar\String_)#5927 (2) {
["value"]=>
string(3) "FOO"
["attributes":protected]=>
array(3) {
["startLine"]=>
int(2)
["endLine"]=>
int(2)
["kind"]=>
int(1)
}
}
["attributes":protected]=>
array(2) {
["startLine"]=>
int(2)
["endLine"]=>
int(2)
}
}
["attributes":protected]=>
array(2) {
["startLine"]=>
int(2)
["endLine"]=>
int(2)
}
}
["attributes":protected]=>
array(2) {
["startLine"]=>
int(2)
["endLine"]=>
int(2)
}
}
}注意带有PhpParser\Node\Scalar\String_的["value"]=> string(3) "FOO"对象
发布于 2019-08-15 02:05:36
对象的实例总是不相等的。您可以像编写其他答案那样编写一个比较函数,但只需将所有受保护的属性都隐藏起来并保留公共属性,只需将其编码为JSON即可。那么比较字符串就足够了。
这里的一个例子
http://sandbox.onlinephpfunctions.com/code/174b9bf5317a200dd42a83c082d3c95558baae90
发布于 2019-08-19 21:23:52
我还没有能够用您的确切数据来测试这一点,但是这个概念应该是可行的。
/**
* Test if two variables are the same, excluding protected properties of objects.
* @return boolean
*/
function compare_public($a, $b) {
// If $a and $b are different things, they're not the same :)
if (gettype($a) != gettype($b)) {
return false;
}
if (is_array($a)) {
// If $a and $b have different lengths, they're not the same.
if (count($a) != count($b)) {
return false;
}
// Call this function recursively to compare each element of $a and $b.
// If any returns false, $a and $b are not the same.
return count(array_filter(array_map(compare_public, $a, $b))) == count($a);
} elseif (is_object($a)) {
// If $a and $b are different classes, they're not the same.
if (get_class($a) != get_class($b)) {
return false;
}
// Use reflection to find all the public properties and compare them.
// Return false if any property is different.
$c = new ReflectionClass(get_class($a));
foreach ($c->getProperties(ReflectionProperty::IS_PUBLIC) as $p) {
if (!compare_public($a->{$p->name}, $b->{$p->name})) { return false; }
}
// All the properties matched. Return true.
return true;
} else {
// Straightforward comparison for non-array, non-objects.
return $a === $b;
}
}这里是一个人为的例子。
class TestObject
{
public $a;
public $b;
protected $c;
public function __construct($a, $b, $c)
{
$this->a = $a; $this->b = $b; $this->c = $c;
}
}
// V V <- protected properties
$first = [new TestObject(new TestObject(1, 2, 3), 2, 3)];
$second = [new TestObject(new TestObject(1, 2, 4), 2, 4)];
var_dump($first, $second, compare_public($first, $second));输出:
array(1) {
[0]=>
object(TestObject)#1 (3) {
["a"]=>
object(TestObject)#2 (3) {
["a"]=>
int(1)
["b"]=>
int(2)
["c":protected]=>
int(3)
}
["b"]=>
int(2)
["c":protected]=>
int(3)
}
}
array(1) {
[0]=>
object(TestObject)#3 (3) {
["a"]=>
object(TestObject)#4 (3) {
["a"]=>
int(1)
["b"]=>
int(2)
["c":protected]=>
int(4)
}
["b"]=>
int(2)
["c":protected]=>
int(4)
}
}
bool(true)发布于 2019-08-20 15:36:20
您可以使用Node遍历器删除该属性。请参阅文档这里。
你的节点穿越器会像这样,
use PhpParser\Node;
use PhpParser\NodeVisitorAbstract;
class MyNodeVisitor extends NodeVisitorAbstract
{
public function leaveNode(Node $node) {
// You might want to do additional checks here
$node->setAttributes([]);
}
}它将删除Parser设置的所有受保护的属性。
尽管正如其中一个注释所示,您将无法使用PHPUnit断言来比较节点,因为这两个节点实例并不相同。但是,您可能可以为测试编写自定义断言。
https://stackoverflow.com/questions/57434444
复制相似问题