序言:
我所追求的是;如果方法调用get_typed_ancestor()
方法,则执行get_typed_ancestor()
中所需操作所需的类名是调用方法定义的类的名称。
传递$this
以提取类名失败,因为它将解析为具体类。如果调用方法是在层次结构中定义的抽象类中定义的,而不是实例所在的具体类,则会得到不正确的类名。
由于与上述相同的原因,寻找instanceof static
失败。
如下所述,捕获定义方法的类名的目的是使get_typed_ancestor()
能够找到从定义调用方法的类派生的任何类的实例,而不仅仅是启动调用堆栈的具体类的另一个实例(因此$this
和static
不满意)
到目前为止,将__CLASS__
传递给get_typed_ancestor()
似乎是迄今为止唯一的解决方案,因为__CLASS__
将正确解析为定义调用方法的类名,而不是调用调用方法的实例的类名。
注意:
我在这个问题的最后列出了一个示例,显示了工作__CLASS__
参数方法和失败的static
方法。如果你想要刺伤,也许可以将其作为一个开始。
问题:
我已经看到几个“解决方案”浮动利用debug_backtrace()
来捕获给定方法或函数的调用类;然而,就我而言,这些(作为我的引号可能暗示)并不完全是解决方案,因为以这种方式使用debug_backtrace()
是一种黑客攻击。
抛开一边,如果这个黑客是唯一的答案,那么我就会破解。
反正;我正在研究一组在底部到顶部可遍历树中充当节点的类。这是一个类层次结构,简化为简洁:
abstract class AbstractNode{}
abstract class AbstractComplexNode extends AbstractNode{}
class SimpleNode extends AbstractNode{}
class ComplexNodeOne extends AbstractComplexNode{}
class ComplexNodeTwo extends AbstractComplexNode{}
节点可以具有任何具体节点(或null
)作为父节点。查看AbstractNode
:
abstract class AbstractNode{
protected $_parent;
public function get_typed_ancestor(){
// here's where I'm working
}
public function get_parent(){
return $this->_parent;
}
}
方法get_typed_ancestor()
就在我所在的位置。
从扩展类中的其他方法调用get_typed_ancestor()
来查找该方法所属的类类型中最接近的_parent
。用一个例子可以更好地说明这一点;鉴于之前的AbstractNode
定义:
abstract class AbstractComplexNode extends AbstractNode{
public function get_something(){
if(something_exists()){
return $something;
}
$node = $this->get_typed_ancestor();
if(null !== $node){
return $node->get_something();
}
}
}
从get_typed_ancestor()
的上下文调用时,方法AbstractComplexNode::get_something()
将寻找类型对象(或扩展类型)AbstractComplexNode
- 在此层次结构的情况下,可能的具体类为ComplexNodeOne
和ComplexNodeTwo
。
由于AbstractComplexNode
无法实例化,因此ComplexNodeOne
等具体实例将调用get_something()
。
我需要在此强调一点; 此前一案例中的搜索必须用于AbstractComplexNode
才能找到ComplexNodeOne
的第一个实例1}}或ComplexNodeTwo
。正如稍后将要解释的那样,搜索和instanceof static
将失败,因为它可能会跳过兄弟班和/或他们的孩子。
问题是,因为有些情况下调用类是抽象的,并且调用方法是由(继承,因此从的实例调用)继承的诸如ComplexNodeOne
之类的类,搜索instanceof
static
的父级不起作用,因为static
后期绑定到具体的ComplexNodeOne
。
现在,我有一个解决方案,但我不喜欢它:
abstract class AbstractNode{
public function get_typed_ancestor($class){
$node = $this;
while(null !== $node->_parent){
if($node->_parent instanceof $class){
return $node->_parent;
}
$node = $node->_parent;
}
return null;
}
}
abstract class AbstractComplexNode extends AbstractNode{
public function get_something(){
if(something_exists()){
return $something;
}
$node = $this->get_typed_ancestor(__CLASS__);
if(null !== $node){
return $node->get_something();
}
}
}
这似乎有效,因为__CLASS__
解析为定义的类名。不幸的是,我尝试使用__CLASS__
作为get_typed_ancestor()
的默认参数但没有成功(虽然这是预期的)
我正在考虑将$class
参数作为可选参数保留,但是如果它可以“隐式”将这些数据传递给方法(没有可选参数)那会很棒。
解决方案/失败:
将__CLASS__
从调用方法作为参数传递给get_typed_ancestor()
可行,但不理想,因为我希望get_typed_ancestor()
解析调用类而不明确告知它。
在搜索循环中,检查if($node->_parent instanceof static)
。
当调用类继承调用方法时不起作用。它解析为调用方法的具体类,而不是定义的方法。这种失败当然也适用于self
和parent
。
使用debug_backtrace()
捕获$trace[1]['class']
并将其用于检查
可行,但并不理想,因为它是一个黑客。
讨论分层数据结构和支持类层次结构是一件很棘手的事情,而不会让您感到困惑。
示例:
abstract class AbstractNode
{
protected $_id;
protected $_parent;
public function __construct($id, self $parent = null)
{
$this->_id = $id;
if(null !== $parent)
{
$this->set_parent($parent);
}
}
protected function get_typed_ancestor_by_class($class)
{
$node = $this;
while(null !== $node->_parent)
{
if($node->_parent instanceof $class)
{
return $node->_parent;
}
$node = $node->_parent;
}
return null;
}
public function get_typed_ancestor_with_static()
{
$node = $this;
while(null !== $node->_parent)
{
if($node->_parent instanceof static)
{
return $node->_parent;
}
$node = $node->_parent;
}
return null;
}
public function set_parent(self $parent)
{
$this->_parent = $parent;
}
}
class SimpleNode extends AbstractNode
{
}
abstract class AbstractComplexNode extends AbstractNode
{
public function test_method_class()
{
var_dump($this->get_typed_ancestor_by_class(__CLASS__));
}
public function test_method_static()
{
var_dump($this->get_typed_ancestor_with_static());
}
}
class ComplexNodeOne extends AbstractComplexNode
{
}
class ComplexNodeTwo extends AbstractComplexNode
{
}
$node_1 = new SimpleNode(1);
$node_2 = new ComplexNodeTwo(2, $node_1);
$node_3 = new SimpleNode(3, $node_2);
$node_4 = new ComplexNodeOne(4, $node_3);
$node_5 = new SimpleNode(5, $node_4);
$node_6 = new ComplexNodeTwo(6, $node_5);
// this call incorrectly finds ComplexNodeTwo ($node_2), skipping
// the instance of ComplexNodeOne ($node_4)
$node_6->test_method_static();
// object(ComplexNodeTwo)#2 (2) {
// ["_id":protected]=>
// int(2)
// ["_parent":protected]=>
// object(SimpleNode)#1 (2) {
// ["_id":protected]=>
// int(1)
// ["_parent":protected]=>
// NULL
// }
// }
// this call correctly finds ComplexNodeOne ($node_4) since it's
// looking for an instance of AbstractComplexNode, resolved from
// the passed __CLASS__
$node_6->test_method_class();
// object(ComplexNodeOne)#4 (2) {
// ["_id":protected]=>
// int(4)
// ["_parent":protected]=>
// object(SimpleNode)#3 (2) {
// ["_id":protected]=>
// int(3)
// ["_parent":protected]=>
// object(ComplexNodeTwo)#2 (2) {
// ["_id":protected]=>
// int(2)
// ["_parent":protected]=>
// object(SimpleNode)#1 (2) {
// ["_id":protected]=>
// int(1)
// ["_parent":protected]=>
// NULL
// }
// }
// }
// }
答案 0 :(得分:1)
要解决问题“捕获给定方法或函数的调用类”,只需在构造函数中传递创建实例的对象。
<?php
class A {
public function caller() {
$b = new B ($this);
$b->bar();
}
}
class B {
$whoClass = '';
public function __construct($who)
{
$this->whoClass = get_class($who);
}
public function bar($who) {
echo get_class($this->whoClass);
}
}