在PHP5.3之前伪造后期静态绑定

在PHP5.3之前伪造后期静态绑定,php,oop,static,Php,Oop,Static,我需要一个继承的静态函数“call”来调用另一个被重写的静态函数“internal”。我可以通过后期静态绑定来实现这一点,但是我的主机还没有php5.3,所以我需要解决它 class ClassA{ static function call() { return self::inner(); } static function inner(){ return "Class A"; } } class ClassB

我需要一个继承的静态函数“call”来调用另一个被重写的静态函数“internal”。我可以通过后期静态绑定来实现这一点,但是我的主机还没有php5.3,所以我需要解决它

class ClassA{
    static function call()
    {
        return self::inner();
    }

    static function inner(){
        return "Class A";
    }   
}

class ClassB extends ClassA{
    static function inner(){
        return "Class B";
    }
}

echo "<p>Class A = " . ClassA::call();
echo "<p>Class B = " . ClassB::call();
A类{
静态函数调用()
{
返回self::inner();
}
静态函数内(){
返回“A类”;
}   
}
类B扩展了类A{
静态函数内(){
返回“B类”;
}
}
回声“Class A=”。ClassA::call();
echo“B类=“。ClassB::call();
我希望输出为:
A类=A类
B类=B类

但它是什么:
A类=A类
B类=A类


我的直觉告诉我,我应该能够在call()中编写一些东西来检测在调用“call()时引用了什么对象。因此,与其使用self::inner(),不如使用与calledclass::inner()类似的内容。检测要从原始方法调用的inner()的正确版本。

不幸的是,没有很好的方法可以做到这一点(否则PHPers不会为该特性感到高兴)

您必须传递类名。PHP<5.3对于使用动态类名的静态调用也没有很好的语法,这使得整个过程更加丑陋:

static function call($class)
{
    return call_user_func(array($class,"inner"));
}
…
ClassA::call("ClassA");
ClassB::call("ClassB");
如果您可以更改代码(而不使用
static
),那么单例将使其更易于接受。您可以使用helper函数简化语法:

X("ClassA")->call();
X("ClassB")->call();

X函数应该查找、创建和返回类的实例。

您可以使用对象实例而不是类。如果需要全局符号,可以使用全局变量。由于它们在PHP中相当笨拙,一个技巧是将其包装到函数中。例如:

class ClassA {
  function call() {
    return $this->inner();
  }
  function inner() {
    return "Class A";
  }   
}
function ClassA() {
  static $instance;
  return $instance ? $instance : new ClassA();
}

class ClassB extends ClassA {
  function inner() {
    return "Class B";
  }
}
function ClassB() {
  static $instance;
  return $instance ? $instance : new ClassB();
}

echo "<p>Class A = " . ClassA()->call();
echo "<p>Class B = " . ClassB()->call();
A类{
函数调用(){
返回$this->internal();
}
函数内部(){
返回“A类”;
}   
}
函数ClassA(){
静态$实例;
返回$instance?$instance:new ClassA();
}
类B扩展了类A{
函数内部(){
返回“B类”;
}
}
函数类B(){
静态$实例;
返回$instance?$instance:new ClassB();
}
回声“Class A=”。ClassA()->call();
echo“B类=“。ClassB()->call();

但更好的办法可能是完全避免使用全球符号;它在Ruby/Rails中运行良好的原因是Ruby并不像PHP那样具有静态。一个类可以在运行时反弹并添加到中,这样可以方便地扩展框架。在PHP中,类总是最终的,因此在应用程序代码中引用它们是一种非常强的耦合。

如果性能不是问题,可以使用debug\u backtrace()查找被调用的类:

$bt = debug_backtrace();
return get_class($bt[1]['object']); 

通常,当一个子对象回调父对象的方法,而父对象又调用该子对象的抽象静态方法时,需要后期静态绑定。我处于这样的位置,不能使用static::因为我的PHP不是5.3版(或更高版本)。下面是通过debug_backtrace()完成的后期静态绑定

抽象类父类
{
静态函数父函数_方法()
{
$child_class_str=self::get_child_class();
eval(\$r=“.child\u class\u str::abstract\u static();”);
返回$r;
}//子级必须重写才能将其自身放入跟踪
受保护的抽象静态函数abstract_static();//这需要后期静态绑定
私有静态函数get_child_class()
{
$backtrace=debug_backtrace();
$num=计数($backtrace);
对于($i=0;$i<$num;$i++)
{
如果($backtrace[$i][“class”]!==\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
返回$backtrace[$i][“类”];
}
返回null;
}
}
类ChildClass扩展了ParentClass
{
静态函数parent_method(){返回parent::parent_method();}
受保护的静态函数抽象_static()
{
返回uuu方法uuu.“()”;
}//来自家长阶级
}
打印“电话号码:”。ChildClass::parent_方法();

因为您不能使用static::,或调用\u class(),或\u调用static, 您必须调用带有指示的inner()函数 被调用的类(如其他答案中所述)。实例 被调用的类中的任何一个都可以。 您可以添加“伪静态”方法来模仿每个静态方法 您需要覆盖。这会使代码加倍,但是 通过如下操作,我希望代码能够更容易升级一次 php5.3出现了:只需删除所有ps方法和 引用它们的函数(并在需要时将“self”更改为“static”)

A类{
静态函数调用()
{
返回self::inner();
}
静态函数内(){
返回“A类”;
} 
公共函数_ps_call()
{
返回$this->_ps_inner();
}
}
类B扩展了类A{
公共静态函数getInstance()
{
返回新的自我();
}
公共静态函数调用()
{
返回self::getInstance()->\u ps_call();
}
静态函数内()
{
返回“B类”;
}   
公共功能
{
返回self::inner();
}
}
回声“Class A=”。ClassA::call();
echo“B类=“。ClassB::call();

下面是一个简单的例子

<?php

class ClassA{
   public function call(){
      return $this->inner();
   }

   static function inner(){
      return "Class A";
   }

   static function init($class){
      return new $class();
   }   
}

class ClassB extends ClassA{
   static function inner(){
      return "Class B";
   }
}

echo "<p>Class A = " . ClassA::init("ClassA")->call();
echo "<p>Class B = " . ClassB::init("ClassB")->call();

?>


如果您不喜欢传入类名,可以向子类添加一个静态init函数,并显式地将其传递给子类。这将允许您执行类似于:ClassA::init()->call()和ClassB::init()->call()的操作,但会有一些较小的代码重复。

因此,基本上可以通过对代码进行结构化来完全避免此问题,这样就不必这样做,或者等到5.3?您还可以使用单例,将实例代码包装在静态函数getInstance()中,并使用函数classB(){return classB::getInstance();}。。如果将静态变量添加到示例中,这将变得更加复杂。在getInstance()方法中,可以复制
class ClassA{
    static function call()
    {
        return self::inner();
    }

    static function inner(){
        return "Class A";
    } 

    public function _ps_call()
    {
        return $this->_ps_inner();
    }


}

class ClassB extends ClassA{

    public static function getInstance() 
    {
        return new self();
    }

    public static function call() 
    {
        return self::getInstance()->_ps_call();
    }

    static function inner()
    {
        return "Class B";
    }   

    public function _ps_inner()
    {
        return self::inner();
    }
}

echo "<p>Class A = " . ClassA::call();
echo "<p>Class B = " . ClassB::call();
<?php

class ClassA{
   public function call(){
      return $this->inner();
   }

   static function inner(){
      return "Class A";
   }

   static function init($class){
      return new $class();
   }   
}

class ClassB extends ClassA{
   static function inner(){
      return "Class B";
   }
}

echo "<p>Class A = " . ClassA::init("ClassA")->call();
echo "<p>Class B = " . ClassB::init("ClassB")->call();

?>