在PHP5.3之前伪造后期静态绑定
我需要一个继承的静态函数“call”来调用另一个被重写的静态函数“internal”。我可以通过后期静态绑定来实现这一点,但是我的主机还没有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
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();
?>