PHP'de geç statik bağlamalar tam olarak nedir?


Yanıtlar:


198

Geç Statik Bağlamaları mutlaka okumalısınız PHP kılavuzunda . Ancak, size kısa bir özet vermeye çalışacağım.

Temel olarak, selfanahtar kelimenin aynı miras kurallarına uymadığı gerçeğine dayanır . selfher zaman kullanıldığı sınıfa gider. Bu, üst sınıfta bir yöntem yapar ve bunu alt sınıftan çağırırsanız self, çocuğa beklediğiniz gibi başvurmayacağı anlamına gelir.

Geç statik bağlama, staticanahtar kelime için bu özel eksikliği gideren yeni bir kullanım sağlar . Kullandığınızda static, ilk kullandığınız sınıfı, yani temsil eder. çalışma zamanı sınıfına 'bağlanır'.

Bunlar arkasındaki iki temel kavram. Yolu self, parentve staticne zaman işletmek staticdaha detaylara yer ince, bu yüzden ziyade gitmek olabilir oyunda, şiddetle manuel sayfa örneklerini incelemek öneriyoruz. Her bir anahtar kelimenin temellerini anladıktan sonra, ne tür sonuçlar elde edeceğinizi görmek için örnekler oldukça gereklidir.


Bu makaleyi gerçekten yararlı ve açıklayıcı buldum, kontrol et [link] ( techflirt.com/tutorials/oop-in-php/late-static-binding.html )
Sadegh Shaikhi

“... selfanahtar kelime miras kurallarına uymuyor. selfher zaman kullanıldığı sınıfa gider.” - Bu self, tıpkı statik olmayan yöntemlerde olduğu gibi, bir üst nesneden ebeveynin statik yöntemini çağıramayacağınız anlamına gelmez . Belki de doğru olanı kastediyorsun, ama bunu yeniden ifade etmelisin. Her şey ancak çocuklar aynı adlı üyelere sahip olduklarında gerçekten önemlidir, çünkü static::bunun yerine hangilerine başvuracağınıza karar verebilirsiniz .
DanMan

81

Gönderen PHP: Duruk - Manuel :

PHP 5.3.0'dan itibaren PHP, statik miras bağlamında çağrılan sınıfa başvurmak için kullanılabilen geç statik bağlanma adı verilen bir özellik uygular.

Geç statik bağlama, başlangıçta çalışma zamanında çağrılan sınıfa başvuran bir anahtar sözcük girerek bu sınırlamayı çözmeye çalışır. ... Yeni bir anahtar kelime getirmemeye static, daha önce ayrılmış olan anahtar kelimeyi kullanmaya karar verildi.

Bir örnek görelim:

<?php
    class Car
    {
        public static function run()
        {
            return static::getName();
        }

        private static function getName()
        {
            return 'Car';
        }
    }

    class Toyota extends Car
    {
        public static function getName()
        {
            return 'Toyota';
        }
    }

    echo Car::run(); // Output: Car
    echo Toyota::run(); // Output: Toyota
?>

Geç statik bağlamalar, son "yönlendirme olmayan çağrıda" adı verilen sınıfı saklayarak çalışır. Statik yöntem çağrıları durumunda, bu açıkça adlandırılan sınıftır (genellikle ::operatörün solundaki sınıftır ); statik olmayan yöntem çağrıları durumunda, nesnenin sınıfıdır. Bir "yönlendirme çağrısı" ile tanıtıldı statik biridir self::, parent::, static::, veya, sınıf hiyerarşisinde yukarıya gidiş eğer forward_static_call(). İşlev get_called_class(), çağrılan sınıfın adıyla bir dize almak static::ve kapsamını tanıtmak için kullanılabilir.


1
Bu yazı, alıntı işaretçileri olmadan php.net makalesinin kelimesi kelimesine ~% 80'i içindir .
WoodrowShigeru

22

Çok açık bir davranış yoktur:

Aşağıdaki kod 'alphabeta' üretir.

class alpha {

    function classname(){
        return __CLASS__;
    }

    function selfname(){
        return self::classname();
    }

    function staticname(){
        return static::classname();
    }
}

class beta extends alpha {

    function classname(){
        return __CLASS__;
    }
}

$beta = new beta();
echo $beta->selfname(); // Output: alpha
echo $beta->staticname(); // Output: beta

Ancak, sınıf adı işlevinin bildirimini beta sınıfından kaldırırsak, sonuç olarak 'alphaalpha' alırız.


1
Çok hoş. Aynı şey PHP kılavuzunda da gösterilmiştir, ancak bu çok daha açıktır. Referans için: php.net/manual/en/language.oop5.late-static-bindings.php (bkz.
Örnek

11

Ben kitaptan alıntı yapıyorum: "PHP Master son teknoloji kod yazmak".

Geç statik bağlanma php 5.3 ile sunulan bir özellikti. Statik yöntemleri bir üst sınıftan miras almamıza ve çağrılan alt sınıfı referans göstermemize izin verir.

Bu, statik yöntemlerle soyut bir sınıfa sahip olabileceğiniz ve self :: method () yerine static :: method () gösterimini kullanarak alt sınıfın somut uygulamalarına başvurabileceğiniz anlamına gelir .

Resmi php belgelerine de göz atabilirsiniz: http://php.net/manual/en/language.oop5.late-static-bindings.php


Geç Statik Bağlamayı açıklamanın en açık yolu basit bir örnektir. Aşağıdaki iki sınıf tanımına bir göz atın ve okumaya devam edin.

class Vehicle {
    public static function invokeDriveByStatic() {
        return static::drive(); // Late Static Binding
    }
    public static function invokeStopBySelf() {
        return self::stop(); // NOT Late Static Binding
    }
    private static function drive(){
        return "I'm driving a VEHICLE";
    }
    private static function stop(){
        return "I'm stopping a VEHICLE";
    }
}

class Car extends Vehicle  {
    protected static function drive(){
        return "I'm driving a CAR";
    }
    private static function stop(){
        return "I'm stopping a CAR";
    }
}

Bir Ebeveyn Sınıfı (Araç) ve bir Çocuk Sınıfı (Araba) görüyoruz. Ana Sınıfın 2 genel yöntemi vardır:

  • invokeDriveByStatic
  • invokeStopBySelf

Ana Sınıfın ayrıca 2 özel yöntemi vardır:

  • drive
  • stop

Child Sınıfı 2 yöntemi geçersiz kılar:

  • drive
  • stop

Şimdi genel yöntemleri çağıralım:

  • invokeDriveByStatic
  • invokeStopBySelf

Kendinize sorun: Hangi sınıf invokeDriveByStatic/invokeStopBySelf ? Ebeveyn mi, Çocuk sınıfı mı?

Aşağıya bir göz atın:

// This is NOT Late Static Binding
// Parent class invokes from Parent. In this case Vehicle.
echo Vehicle::invokeDriveByStatic(); // I'm driving a VEHICLE
echo Vehicle::invokeStopBySelf(); // I'm stopping a VEHICLE

// !!! This is Late Static Binding !!!!
// Child class invokes an inherited method from Parent.
// Child class = Car, Inherited method = invokeDriveByStatic().
// The inherited method invokes a method that is overridden by the Child class.
// Overridden method = drive()
echo Car::invokeDriveByStatic(); // I'm driving a CAR

// This is NOT Late Static Binding
// Child class invokes an inherited method from Parent.
// The inherited method invokes a method inside the Vehicle context.
echo Car::invokeStopBySelf(); // I'm stopping a VEHICLE

staticAnahtar kelime bir Singleton tasarım deseni kullanılmıştır. Bkz. Bağlantı: https://refactoring.guru/design-patterns/singleton/php/example


7

Farkı göstermenin en basit örneği.
Not, kendini :: $ c

class A
{
    static $c = 7;

    public static function getVal()
    {
        return self::$c;
    }
}

class B extends A
{
    static $c = 8;
}

B::getVal(); // 7

Geç statik bağlama, not statik :: $ c

class A
{
    static $c = 7;

    public static function getVal()
    {
        return static::$c;
    }
}

class B extends A
{
    static $c = 8;
}

B::getVal(); // 8

4

Örneğin:

abstract class Builder {
    public static function build() {
        return new static;
    }
}

class Member extends Builder {
    public function who_am_i() {
         echo 'Member';
    }
}

Member::build()->who_am_i();

4

"Bunu neden kullanayım?" Bu, temel olarak statik yöntemin yorumlandığı / çalıştırıldığı bağlamı değiştirmenin bir yoludur.

İle self, bağlam yöntemi başlangıçta tanımladığınız bağlamdır. İle staticaradığınız kişi bu.


1

Ayrıca, alt sınıflarda statik değişkenleri güncelleyip güncellemediğinizi de izleyin. Çocuk B'nin çocuk C'yi güncellediği bu (biraz) beklenmedik sonucu buldum:

class A{
    protected static $things;
}

class B extends A {
    public static function things(){
        static::$things[1] = 'Thing B';
        return static::$things; 
    }
}

class C extends A{
    public static function things(){
        static::$things[2] = 'Thing C';
        return static::$things;        
    }
}

print_r(C::things());
// Array (
//   [2] => Thing C
// )

B::things();

print_r(C::things()); 
// Array (
//    [2] => Thing C
//    [1] => Thing B
// )

Her alt sınıfta aynı değişkeni bildirerek düzeltebilirsiniz, örneğin:

class C extends A{
    protected static $things; // add this and B will not interfere!

    public static function things(){
        static::$things[2] = 'Thing C';
        return static::$things;        
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.