Класове и обекти (PHP 5)
PHP Manual

Късно статично свързване

От PHP 5.3.0 в PHP е реализирано късно статично свързване, което може да се използва за обръщане към извикания клас в контекста на статичното наследяване.

Тази възможност неслучайно е наречена "късно статично свързване". "Късно свързване" идва от факта, че static:: вече няма да сочи към класа, в който е дефиниран методът, а ще бъде изчисляван на базата на информацията по време на изпълнение на скрипта. Също така е наречено "статично свързване", тъй като може да се използва (без да е ограничено само в тази употреба) за извикване на статични методи.

Ограничения на self::

Статичните референции към текущия клас като self:: и __CLASS__ се извикват на базата на това на кой клас принадлежи методът, т.е. къде е дефиниран:

Example #1 Употреба на self::

<?php
class {
    public static function 
who() {
        echo 
__CLASS__;
    }
    public static function 
test() {
        
self::who();
    }
}

class 
extends {
    public static function 
who() {
         echo 
__CLASS__;
    }
}

B::test();
?>

Примерът по-горе ще изведе:

A

Употреба на късно статично свързване

С късното статично свързване се прави опит да се премахне това ограничение чрез въвеждането на нова ключова дума, която да сочи към класа, който първоначално е бил извикан по време на изпълнение. На практика това е ключовата дума, която би позволила да се извика B от test() в предишния пример. Веше решено вместо да се въвежда нова ключова дума, да се използва static, която така или иначе вече е запазена.

Example #2 Проста употреба на static::

<?php
class {
    public static function 
who() {
        echo 
__CLASS__;
    }
    public static function 
test() {
        static::
who(); // Here comes Late Static Bindings
    
}
}

class 
extends {
    public static function 
who() {
         echo 
__CLASS__;
    }
}

B::test();
?>

Примерът по-горе ще изведе:

B

Забележка: static:: не работи еквивалентно на $this за статични методи! $this-> следва правилата на наследяването, за разлика от static::. Тази разлика е обяснена по-подробно малко по-късно.

Example #3 Употреба на static:: в нестатичен контекст

<?php
class TestChild extends TestParent {
    public function 
__construct() {
        static::
who();
    }

    public function 
test() {
        
$o = new TestParent();
    }

    public static function 
who() {
        echo 
__CLASS__."\n";
    }
}

class 
TestParent {
    public function 
__construct() {
        static::
who();
    }

    public static function 
who() {
        echo 
__CLASS__."\n";
    }
}
$o = new TestChild;
$o->test();

?>

Примерът по-горе ще изведе:

TestChild
TestParent

Забележка: Решението кой метод да се изпълни при късното статично свързване ще бъде взето при напълно определено статично извикване, без връщане. От друга страна, статичните извиквани посредством ключовите думи като parent:: и self:: ще препратят извикващата информация.

Example #4 Препращащи и непрепращащи извиквания

<?php
class {
    public static function 
foo() {
        static::
who();
    }

    public static function 
who() {
        echo 
__CLASS__."\n";
    }
}

class 
extends {
    public static function 
test() {
        
A::foo();
        
parent::foo();
        
self::foo();
    }

    public static function 
who() {
        echo 
__CLASS__."\n";
    }
}
class 
extends {
    public static function 
who() {
        echo 
__CLASS__."\n";
    }
}

C::test();
?>

Примерът по-горе ще изведе:

A
C
C

Крайни случаи

Съществуват редица различни начини да се извика метод в PHP, като например - обратни извиквания и вълшебни методи. Тъй като, при късното статично свързване, решението кой метод да се изпълни се базира на информацията по време на изпълнение, това може да доведе до неочаквани резултати при т.н. крайни случаи.

Example #5 Късно статично свързване във вълшебни методи

<?php
class {

   protected static function 
who() {
        echo 
__CLASS__."\n";
   }

   public function 
__get($var) {
       return static::
who();
   }
}

class 
extends {

   protected static function 
who() {
        echo 
__CLASS__."\n";
   }
}

$b = new B;
$b->foo;
?>

Примерът по-горе ще изведе:

B

Класове и обекти (PHP 5)
PHP Manual