代码之家  ›  专栏  ›  技术社区  ›  rg88

何时需要使用后期静态绑定?

  •  8
  • rg88  · 技术社区  · 16 年前

    读后 this description 关于后期静态绑定(LSB),我非常清楚地看到了正在发生的事情。现在,在哪种情况下最有用或最需要?

    6 回复  |  直到 16 年前
        1
  •  5
  •   Alex Weinstein    15 年前

    在以下情况下,我需要LSB:

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

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

        2
  •  5
  •   Adam Franco    15 年前

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

    这个 DateAndTime class 是我从smalltalk/squak移植到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减少了这种重复,允许更干净和更直接的实现。

        3
  •  3
  •   Jonathan Amsterdam    16 年前

    当:

    1. 您的功能在类层次结构中有所不同,

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

    3. (关键的是)您没有挂起功能的实例。

    如果只获得1和2,您将使用普通的实例方法。所以亚历克斯的问题(见他对这个问题的回答)不需要LSB。

    典型的情况是对象创建,其中子类以不同的方式创建自己,但使用相同的参数。显然,您没有要调用的实例,因此创建方法(也称为工厂方法)必须是静态的。然而,您希望它的行为因子类而异,所以普通的静态方法是不正确的。请看亚当·弗朗哥的答案。

        4
  •  1
  •   thr    16 年前

    如果需要访问子类中没有重载的方法中的重载静态属性/方法,则需要后期静态绑定。一个简单的例子: paste2.org

    典型的例子是来自Rails的ActiveRecord类,如果您尝试在PHP中实现类似的东西,它看起来像这样: class User extends ActiveRecord 然后试着打电话 User::find(1) 调用的方法实际上是 ActiveRecord::find() 因为你没有超载 find() 在里面 User -但是没有后期的静态绑定 查找() 方法在 ActiveRecord 不知道它是从哪个阶级来的( self 里面总是指向 ActudieCordRD ,因此它无法为您获取用户对象。

        5
  •  1
  •   disc0dancer    15 年前

    假设在简化的对象关系映射器中有表示表(行实例)的类。 您将拥有一个类“用户”和一个类“公司”,其实例表示各自表的行。 用户和公司将从一些基本抽象类继承,比如说“baseobject”,它将具有一些常见的方法,如save()、delete()、validate()等…

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

    如果没有lsb,baseObject中提到的validate()方法将没有对用户和公司中定义的静态变量的引用,即使您是通过用户的实例调用它。它将在BaseObject类中查找相同的静态变量,并将引发错误。

    这是我在php 5.2.8上的经验-lsb将在5.3中介绍

        6
  •  0
  •   Tyson of the Northwest    15 年前

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