你什么时候需要使用后期静态绑定?

时间:2008-09-17 20:20:33

标签: php oop

在阅读了后期静态绑定(LSB)的this description之后,我清楚地看到了发生了什么。现在,哪种情况最有用或最需要?

6 个答案:

答案 0 :(得分:6)

对于以下情况,我需要LSB:

  • 想象一下,您正在构建一个“邮件处理器”守护程序,它从电子邮件服务器下载邮件,对其进行分类,解析,保存,然后执行某些操作,具体取决于邮件的类型。
  • 类层次结构:您有一个基本的Message类,子项为“BouncedMessage”和“AcceptedMessage”。
  • 每种消息类型都有自己的方式在磁盘上保留自己。例如,BouncedMessage类型的所有消息都尝试将自身保存为BouncedMessage-id.xml。另一方面,AcceptedMessage需要以不同的方式保存自己 - 作为AcceptedMessage-timestamp.xml。这里重要的是确定文件名模式的逻辑对于不同的子类是不同的,但对于子类中的所有项都是共享。这就是为什么它在静态方法中才有意义。
  • Base Message类有一个抽象的静态方法(是的,抽象的 AND 静态)“save”。 BouncedMessage使用具体的静态方法实现此方法。然后,在实际检索消息的类中,您可以调用“:: save()”

如果您想了解有关该主题的更多信息:

答案 1 :(得分:5)

我对后期静态绑定的一个主要需求是一组静态实例创建方法。

这个DateAndTime class是我从Smalltalk / Squeak移植到PHP的时间库的一部分。使用静态实例创建方法可以创建具有各种参数类型的实例,同时在静态方法中保持参数检查,以便库的使用者无法获取不完全有效的实例。

在这种情况下,后期静态绑定非常有用,因此这些静态实例创建方法的实现可以确定调用最初所针对的类。以下是一个使用示例:

使用LSB:

class DateAndTime {

    public static function now() {
        $class = static::myClass();
        $obj = new $class;
        $obj->setSeconds(time());
        return $obj;
    }

    public static function yesterday() {
        $class = static::myClass();
        $obj = new $class;
        $obj->setSeconds(time() - 86400);
        return $obj;
    }

    protected static function myClass () {
        return 'DateAndTime';
    }
}

class Timestamp extends DateAndTime {

    protected static function myClass () {
        return 'Timestamp';
    }
}


// Usage:
$date = DateAndTime::now();
$timestamp = Timestamp::now();

$date2 = DateAndTime::yesterday();
$timestamp2 = Timestamp::yesterday();

没有后期静态绑定,[在我当前的实现中]每个类必须实现每个实例创建方法,如下例所示:

没有LSB:

class DateAndTime {

    public static function now($class = 'DateAndTime') {
        $obj = new $class;
        $obj->setSeconds(time());
        return $obj;
    }

    public static function yesterday($class = 'DateAndTime') {
        $obj = new $class;
        $obj->setSeconds(time() - 86400);
        return $obj;
    }

}

class Timestamp extends DateAndTime {

    public static function now($class = 'Timestamp') {
        return self::now($class);
    }

     public static function yesterday($class = 'Timestamp') {
        return self::yesterday($class);
    }

}

随着实例创建方法和类层次结构的数量增加,方法的重复成为了一个真正的痛苦。 LSB减少了这种重复,并允许更清晰,更直接的实现。

答案 2 :(得分:3)

在以下情况下有用:

  1. 您的功能因类层次结构而异,

  2. 该功能在层次结构上具有相同的签名,并且

  3. (至关重要)您没有实例来挂起功能。

  4. 如果只获得#1和#2,则使用普通的实例方法。所以Alex的问题(见他对这个问题的回答)并不需要LSB。

    典型的情况是对象创建,其中子类以不同的方式创建自己,但使用相同的参数。显然,您没有要调用的实例,因此创建方法(也称为工厂方法)必须是静态的。但是你希望它的行为根据子类而变化,所以普通的静态方法是不对的。请参阅Adam Franco的答案。

答案 3 :(得分:1)

如果需要在尚未在子类中重载的方法中访问重载的静态属性/ Method,则需要延迟静态绑定。一个简单的例子:paste2.org

经典的例子是来自Rails的ActiveRecord类,如果你试图在PHP中实现类似的东西,它看起来像这样:class User extends ActiveRecord然后尝试调用User::find(1)被调用的方法是实际上是ActiveRecord::find(),因为您没有在find()中重载User - 但是如果没有后期静态绑定,find()中的ActiveRecord方法无法知道哪个归类于self从(ActiveRecord中调用它将始终指向{{1}}),因此它无法为您获取用户对象。

答案 4 :(得分:1)

假设您在简化的对象关系映射器中有表示表(行实例)的类。 您将拥有一个“User”类和一个“Company”类,其实例表示各个表的行。 用户和公司将从一些基础抽象类继承,让我们说“BaseObject”将有一些常见的方法,如save(),delete(),validate()等...

如果要存储有关验证和表定义的数据,最好的位置是每个派生类中的静态变量 - 因为验证和表定义对于每个User实例都是相同的。

如果没有LSB,BaseObject中提到的validate()方法将不会引用User和Company中定义的静态变量,即使您是通过User实例调用它。它将在Ba​​seObject类中查找相同的静态变量,并且会引发错误。

这是我使用PHP 5.2.8的经验 - LSB将在5.3中引入

答案 5 :(得分:0)

我有一个带有静态方法的类来处理一些格式化。我有另一个类,除了它如何处理格式化之外,还需要原始函数的所有功能。