是否可以直接在PHP对象上使用XPath语法来浏览对象的层次结构?
也就是说,我可以使用(2)代替(1):
$object->subObject1->subObject2
$object['subObject1/subObject2']
(括号中的表达式是XPath。)根据我目前的理解,将对象转换为ArrayObject没有意义,因为XPath不能与ArrayObjects一起使用。这是对的吗?
答案 0 :(得分:2)
如果您只需要基于/
- 分隔路径的基本遍历,那么您可以使用这样的简单循环实现它:
public function getDescendant($path) {
// Separate the path into an array of components
$path_parts = explode('/', $path);
// Start by pointing at the current object
$var = $this;
// Loop over the parts of the path specified
foreach($path_parts as $property)
{
// Check that it's a valid access
if ( is_object($var) && isset($var->$property) )
{
// Traverse to the specified property,
// overwriting the same variable
$var = $var->$property;
}
else
{
return null;
}
}
// Our variable has now traversed the specified path
return $var;
}
设置一个值是类似的,但是我们需要一个额外的技巧:为了能够在循环退出后分配一个值,我们需要每次通过引用分配变量:
public function setDescendant($path, $value) {
// Separate the path into an array of components
$path_parts = explode('/', $path);
// Start by pointing at the current object
$var =& $this;
// Loop over the parts of the path specified
foreach($path_parts as $property)
{
// Traverse to the specified property,
// overwriting the same variable with a *reference*
$var =& $var->$property;
}
// Our variable has now traversed the specified path,
// and is a reference to the variable we want to overwrite
$var = $value;
}
将这些添加到名为Test
的类中,允许我们执行以下操作:
$foo = new Test;
$foo->setDescendant('A/B', 42);
$bar = new Test;
$bar->setDescendant('One/Two', $foo);
echo $bar->getDescendant('One/Two/A/B'), ' is the same as ', $bar->One->Two->A->B;
要在问题中使用数组访问表示法来允许此操作,您需要创建一个实现the ArrayAccess
interface的类:
offsetGet
和offsetSet
offsetExists
与getDescendant
/ offsetGet
类似,只是返回false
而不是null
,而true
代替$var
}}。offsetUnset
稍微麻烦一点,因为您无法使用引用分配技巧从其父对象中实际删除属性。相反,您需要特别处理指定路径的最后一部分,例如用array_pop($path_parts)
另一个想法是,这可能是a Trait
的一个很好的候选者,它基本上允许您将函数复制并粘贴到不相关的类中。请注意,Traits无法直接实现接口,因此每个类都需要特性的implements ArrayAccess
和use
语句。
(当我有时间时,我可以回来编辑ArrayAccess
方法的完整示例。)
答案 1 :(得分:0)
对于某些依赖项,它应该(很容易)支持完整的XPath表达式集。唯一的困难是从 完全限定的XPath实现遍历对象。
DOMDocument
,运行您的任意XPath表达式并从所选元素中获取节点路径($node->getNodePath()
),如图所示here /blah/example[2]/x[3]
的节点路径,您现在可以使用object attribute iteration以递归方式在对象上实现遍历。这在很大程度上取决于1中的序列化器的实际工作方式。 注意:我不知道实际是否需要实施ArrayAccess
界面,因为您可以使用$obj->$key
访问$key
等对象属性是一些从节点路径切成的字符串。