首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何比较排除受保护属性的两个节点?(PHP-Parser)

如何比较排除受保护属性的两个节点?(PHP-Parser)
EN

Stack Overflow用户
提问于 2019-08-09 17:02:57
回答 3查看 214关注 0票数 0

我在我的项目中使用PHP-分析器。我想用PHPUnitassertEquals函数比较两个节点。

尽管节点是相同的,但它提供了一个错误的结果。原因是,其中一个节点包含两个受保护的属性,而另一个节点不包含:

代码语言:javascript
复制
["attributes":protected]=>
array(2) {
  ["startLine"]=>
  int(2)
  ["endLine"]=>
  int(2)
}

可以比较排除受保护属性的节点吗?

示例数据

第一个目标是:

代码语言:javascript
复制
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)
    }
  }
}

第二个目标是:

代码语言:javascript
复制
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"对象

EN

回答 3

Stack Overflow用户

发布于 2019-08-15 02:05:36

对象的实例总是不相等的。您可以像编写其他答案那样编写一个比较函数,但只需将所有受保护的属性都隐藏起来并保留公共属性,只需将其编码为JSON即可。那么比较字符串就足够了。

这里的一个例子

http://sandbox.onlinephpfunctions.com/code/174b9bf5317a200dd42a83c082d3c95558baae90

票数 0
EN

Stack Overflow用户

发布于 2019-08-19 21:23:52

我还没有能够用您的确切数据来测试这一点,但是这个概念应该是可行的。

代码语言:javascript
复制
/**
 * 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;
    }
}

这里是一个人为的例子。

代码语言:javascript
复制
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));

输出:

代码语言:javascript
复制
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)
票数 0
EN

Stack Overflow用户

发布于 2019-08-20 15:36:20

您可以使用Node遍历器删除该属性。请参阅文档这里

你的节点穿越器会像这样,

代码语言:javascript
复制
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断言来比较节点,因为这两个节点实例并不相同。但是,您可能可以为测试编写自定义断言。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57434444

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档