扩展PHP静态类

19

我在这个领域已经苦苦挣扎了几天,虽然我得出了一个结论,但是由于这个结论不是我想要的,所以在放弃之前,我会尝试看看其他人说什么。信念最后死去...

假设我们有一个超类(称为“Super”)和一个子类(称为“Sub”)。

class Super {
    protected static $title = 'super';
    public static function get_class_name()        
    {
        echo __CLASS__;
    }
    public static function get_title()
    {
        echo self::$title;
    }
}
class Sub extends Super {
    protected static $title = 'sub';
}
现在,您可能期望由于Sub扩展了Super,Sub现在将继承所有Super的方法,然而,它似乎只接收到对Sub方法的引用。
我这样说是因为如果我调用:
Sub::get_class_name();

输出是"Super"而不是"Sub"。

如果我调用:

Sub::get_title();

再次运行代码,输出结果为“super”,即使我在子类中声明了$title。

这意味着,当我调用一个继承的静态函数时,函数的作用域将是超类,而不是被调用的那个类(即使你打印回溯,它也会显示调用是在超类上进行的!!!),为了获得作用域为调用该方法的子类,我需要在该子类中重新声明该方法。 这种情况似乎违背了扩展类的目的,不是吗?

因此,我的问题是:我是否可以扩展一个静态类,调用其中一个继承的方法,并具有子类的范围? 或者至少能够识别它的类名? 如果不能,为什么我要扩展静态类呢?

谢谢!

3个回答

33

在 PHP 5.3.0 之前是不可能的。

延迟静态绑定是在 PHP 5.3.0 中引入的,可以通过 static 关键字实现您想要的功能。

class Super {
    protected static $title = 'super';
    public static function get_class_name()        
    {
        echo __CLASS__;
    }
    public static function get_title()
    {
        echo static::$title;
    }
}
class Sub extends Super {
    protected static $title = 'sub';
}

get_class_name()可能会返回Super,尽管它的__CLASS__始终返回声明该方法的当前类(有点像__FILE__,它始终返回当前文件,无论您是否包含了它)。

因此,您别无选择,只能在Sub类中重新声明该函数。

class Super {
    protected static $title = 'super';
    public static function get_class_name()        
    {
        echo __CLASS__;
    }
    public static function get_title()
    {
        echo static::$title;
    }
}
class Sub extends Super {
    protected static $title = 'sub';

    public static function get_class_name()        
    {
        echo __CLASS__;
    }
}

3

您可以使用get_called_class()来获取您正在调用的类的类名,即使它是静态的。您不需要在任何地方声明它。

以下是安德鲁的示例:

class Super {
    public static function get_class1_name()        
    {
        echo __CLASS__;
    }
    public static function get_title()
    {
        echo get_called_class();
    }

}
class Sub extends Super {    
    public static function get_class2_name()        
    {
        echo __CLASS__;
    }

}
Sub::get_title(); // Echos Sub.
Sub::get_class1_Name(); // echos super
Sub::get_class2_Name(); // echos sub

因此,您不必声明任何变量。

从PHP 5.3.0开始可用。 - Andrew Moore
这个例子没有涉及到在子类和父类之间访问静态属性的差异。 - beporter

0

幸运的是,我正在为自己做一些事情,所以我说了算,我使用PHP5.3。但即便如此,我也不喜欢在每个类中都必须重新声明“get_class_name”,可能我正在扩展10个类。所以我想出了这个解决方案:

class Super {
    protected static $classname = __CLASS__;
    public static function get_classname($name)
    {
        static::$classname = $name;
    }
    public static function get_classname()
    {
        return static::$classname;
    }
}
class Sub1 extends Super { }
class Sub2 extends Super { }
class Sub3 extends Super { }

$classes = get_declared_classes();
foreach($classes as $k => $v)
{
    if (is_subclass_of($v, 'Super'))
    {
        $v::set_classname($v);
    }
}

echo Sub1::get_classname(); // Sub1
echo Sub2::get_classname(); // Sub2
echo Sub3::get_classname(); // Sub3

看起来有点不规矩,但我觉得并不算太糟糕。完成这个步骤后,你终于可以扩展静态方法,而无需重新声明方法。


2
正如Chacha102的回答中所提到的,PHP 5.3还具有get_called_class()函数,这使得这种解决方法变得多余。 - MrWhite

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接