When would you need to use late static binding?

2020-02-09 10:59发布

问题:

After reading this description of late static binding (LSB) I see pretty clearly what is going on. Now, under which sorts of circumstances might that be most useful or needed?

回答1:

I needed LSB this for the following scenario:

  • Imagine you're building a "mail processor" daemon that downloads the message from an email server, classifies it, parses it, saves it, and then does something, depending on the type of the message.
  • Class hierarchy: you have a base Message class, with children "BouncedMessage" and "AcceptedMessage".
  • Each of the message types has its own way to persist itself on disk. For example, all messages of type BouncedMessage try to save itself as BouncedMessage-id.xml. AcceptedMessage, on the other hand, needs to save itself differently - as AcceptedMessage-timestamp.xml. The important thing here is that the logic for determining the filename pattern is different for different subclasses, but shared for all items within the subclass. That's why it makes sense for it to be in a static method.
  • Base Message class has an abstract static method (yes, abstract AND static) "save". BouncedMessage implements this method with a concrete static method. Then, inside the class that actually retrieves the message, you can call "::save()"

If you want to learn more about the subject:

  • http://www.qcodo.com/forums/topic.php/2356
  • http://community.livejournal.com/php/585907.html
  • http://bugs.php.net/bug.php?id=42681


回答2:

One primary need I have for late static binding is for a set of static instance-creation methods.

This DateAndTime class is part of a chronology library that I ported to PHP from Smalltalk/Squeak. Using static instance-creation methods enables creation of instances with a variety of argument types, while keeping parameter checking in the static method so that the consumer of the library is unable to obtain an instance that is not fully valid.

Late static binding is useful in this case so that the implementations of these static instance-creation methods can determine what class was originally targeted by the call. Here is an example of usage:

With 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();

Without late static binding, [as in my current implementation] each class must implement every instance creation method as in this example:

Without 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);
    }

}

As the number of instance-creation methods and class-hierarchy increases the duplication of methods becomes a real pain in the butt. LSB reduces this duplication and allows for much cleaner and more straight-forward implementations.



回答3:

It's useful when:

  1. You have functionality that varies over the class hierarchy,

  2. The functionality has the same signature over the hierarchy, and

  3. (crucially) You don't have an instance to hang the functionality off of.

If only #1 and #2 obtained, you would use an ordinary instance method. So Alex's problem (see his answer to this question) does not require LSB.

A typical case is object creation, where subclasses create themselves in different ways, but using the same parameters. Obviously you have no instance to call, so the creation method (also known as a factory method) must be static. Yet you want its behavior to vary depending on the subclass, so an ordinary static method is not right. See Adam Franco's answer for an example.



回答4:

If you need to access an overloaded static property/Method within a method that hasn't been overloaded in a subclass - you need late static binding. A quick example: paste2.org

The classic example is the ActiveRecord class from Rails, if you try to implement something similar in PHP, which would look like this: class User extends ActiveRecord and then try to call User::find(1) the method that gets called is actually ActiveRecord::find() because you haven't overloaded find() in User - but without late static binding the find() method in ActiveRecord has no way of knowing which classed it got called from (self within it will always point to ActiveRecord), and thus it can't fetch your User-object for you.



回答5:

Suppose you have classes representing tables (row instances) in a simplified object-relational mapper. You would have a class "User" and a class "Company" who's instances are representing rows of the respective tables. User and Company would inherit from some base abstract class, let's say "BaseObject" that will have some common methods like save(), delete(), validate() etc ...

If you want to store data about the validation and the table definition, the best place would be in a static variable in each derived class - since the validation and table definition is the same for each instance of User.

Without LSB the mentioned validate() method in BaseObject would have no reference to the static variables defined in User and Company, even though you are calling it through an instance of User. It will look for the same static variable in the BaseObject class, and it will raise an error.

This is my experience with PHP 5.2.8 - LSB is going to be introduced in 5.3



回答6:

I have a class with a static method that handles some formatting. I have another class that than needs all the functionality of the original one except for how it handles formatting.



标签: php oop