看一下这个示例,并注意指示的输出。
<?php
class Mommy
{
protected static $_data = "Mommy Data";
public static function init( $data )
{
static::$_data = $data;
}
public static function showData()
{
echo static::$_data . "<br>";
}
}
class Brother extends Mommy
{
}
class Sister extends Mommy
{
}
Brother::init( "Brother Data" );
Sister::init( "Sister Data" );
Brother::showData(); // Outputs: Sister Data
Sister::showData(); // Outputs: Sister Data
?>
我的理解是,使用 static 关键字将引用子类,但显然,只要子类中缺少该关键字,它就会神奇地应用于父类。 (这对于 PHP 来说是一种危险的行为,下面将详细解释。)
我之所以要这样做,是出于以下两点考虑:
但是,如果我们想在运行时重写一个属性(通过 init 方法),它将为父类重写它!从那时起,之前初始化的子类(如 Brother 的情况)会意外地在您身上发生变化。
显然,这是由于子类没有自己的静态属性副本(每当子类内部未显式定义该静态属性时),但它不会抛出错误,而是切换 static 的行为来访问父类。因此,是否有某种方法可以让父类动态创建属于子类的属性,而不会出现在子类定义中?这样子类就可以拥有自己的静态属性和静态属性的副本关键字可以正确引用它,并且可以编写它以考虑父属性默认值。
或者还有其他解决方案吗,好、坏还是难看?
它确实引用了正确的类,只是,除非重新声明或引用集被破坏,否则子类中的静态属性与超类中的引用集相同。
所以你必须这样做:
class Brother extends Mommy
{
protected static $_data;
}
或:
class Brother extends Mommy
{
}
$tmp = null;
Brother::$_data =& $tmp;
unset($tmp);
我已经尝试了@Artefacto的第二种方法,该方法对OP的评论中所说的内容有效,但它对我不起作用,也许是因为我的情况更复杂,因为我在一个内部使用它父类中使用的特征,以及我使用 WordPress 钩子,这意味着事情将在不同的时间执行。
尝试不同的事情后,我想出了不同的方法。
它可能不适合所有人,因为它需要将属性更改为数组。另一方面,在我看来,它更干净,因为我们不需要使用
get_called_class()
也不需要使用指针。
<?php
class Mommy
{
protected static $_data = array(
self::class => "Mommy Data"
);
public static function init( $data )
{
static::$_data[static::class] = $data;
}
public static function showData()
{
echo static::$_data[static::class] . "<br>";
}
}
class Brother extends Mommy
{
}
class Sister extends Mommy
{
}
Brother::init( "Brother Data" );
Sister::init( "Sister Data" );
Brother::showData(); // Outputs: Brother Data
Sister::showData(); // Outputs: Sister Data
?>
请注意,我已使用“Mommy data”初始化了数组,但如果您不需要父类的值,则可以将其初始化为空数组。
我希望这对某人有帮助。我自己花了几个小时努力寻找一种干净的方法来做到这一点,而又不放弃保持我的方法静态。