การผูกแบบคงที่ใน PHP คืออะไร?


คำตอบ:


203

คุณต้องอ่านLate Static Bindingsในคู่มือ PHP อย่างแน่นอน อย่างไรก็ตามฉันจะพยายามสรุปให้คุณทราบอย่างรวดเร็ว

โดยพื้นฐานแล้วมันเป็นความจริงที่ว่าselfคีย์เวิร์ดไม่เป็นไปตามกฎการสืบทอดเดียวกัน selfมักจะแก้ไขไปยังคลาสที่ใช้ ซึ่งหมายความว่าหากคุณสร้างเมธอดในคลาสแม่และเรียกใช้จากคลาสลูกselfจะไม่อ้างอิงเด็กอย่างที่คุณคาดหวัง

การผูกแบบคงที่ในช่วงปลายแนะนำการใช้งานใหม่สำหรับstaticคำหลักซึ่งกล่าวถึงข้อบกพร่องนี้ เมื่อคุณใช้staticจะแสดงถึงคลาสที่คุณใช้เป็นครั้งแรกเช่น มัน 'ผูก' กับคลาสรันไทม์

นี่คือแนวคิดพื้นฐานสองประการที่อยู่เบื้องหลัง วิธีself, parentและstaticทำงานเมื่อstaticอยู่ในการเล่นสามารถจะมีความซับซ้อนดังนั้นแทนที่จะไปในรายละเอียดมากขึ้นผมขอแนะนำให้คุณศึกษาตัวอย่างหน้าคู่มือ เมื่อคุณเข้าใจพื้นฐานของคำหลักแต่ละคำแล้วตัวอย่างก็ค่อนข้างจำเป็นในการดูว่าคุณจะได้ผลลัพธ์แบบใด


ฉันพบว่าบทความนี้มีประโยชน์และเป็นคำอธิบายจริงๆลองดู [ลิงค์] ( techflirt.com/tutorials/oop-in-php/late-static-binding.html )
Sadegh Shaikhi

"... selfคีย์เวิร์ดไม่เป็นไปตามกฎของการสืบทอดselfจะแก้ไขเป็นคลาสที่จะใช้เสมอ" - ซึ่งไม่ได้หมายความว่าคุณไม่สามารถเรียกวิธีการแบบคงที่ของผู้ปกครองจากวัตถุลูกผ่านได้selfเช่นเดียวกับวิธีการที่ไม่คงที่ คุณอาจจะหมายถึงสิ่งที่ถูกต้อง แต่คุณควรเรียบเรียงใหม่ ทุกอย่างมีความสำคัญมากเมื่อเด็ก ๆ มีสมาชิกที่มีชื่อเหมือนกันเท่านั้นเนื่องจากคุณสามารถตัดสินใจได้ว่าจะอ้างถึงคนใดโดยใช้static::แทน
DanMan

82

จากPHP: Late Static Bindings - Manual :

ในขณะที่ PHP 5.3.0 PHP ใช้คุณลักษณะที่เรียกว่า late static binding ซึ่งสามารถใช้อ้างอิงคลาสที่เรียกว่าในบริบทของการสืบทอดแบบคงที่

การผูกแบบคงที่ในช่วงปลายพยายามแก้ไขข้อ จำกัด ดังกล่าวโดยการแนะนำคีย์เวิร์ดที่อ้างอิงคลาสที่ถูกเรียกครั้งแรกเมื่อรันไทม์ ... มีการตัดสินใจที่จะไม่แนะนำคีย์เวิร์ดใหม่ แต่เป็นการใช้staticที่ได้จองไว้แล้ว

ลองดูตัวอย่าง:

<?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
?>

การผูกแบบคงที่ปลายจะทำงานโดยการจัดเก็บคลาสที่มีชื่ออยู่ใน "การโทรที่ไม่โอนสาย" ครั้งสุดท้าย ในกรณีของการเรียกเมธอดแบบคงที่นี่คือคลาสที่ตั้งชื่ออย่างชัดเจน (โดยปกติจะเป็นคลาสที่อยู่ทางซ้ายของตัว::ดำเนินการ) ในกรณีของการเรียกเมธอดแบบไม่คงที่เป็นคลาสของอ็อบเจ็กต์ เรียกว่า "ส่งต่อ" เป็นหนึ่งที่คงที่ที่เป็นที่รู้จักโดยself::, parent::, หรือหากจะขึ้นในลำดับชั้นเรียนstatic:: forward_static_call()ฟังก์ชันget_called_class()นี้สามารถใช้เพื่อดึงสตริงที่มีชื่อของคลาสที่เรียกและstatic::แนะนำขอบเขต


1
โพสต์นี้เป็นสำเนาคำต่อคำของบทความ php.netโดยไม่มีเครื่องหมายอ้างอิงถึง 80%
WoodrowShigeru

22

ไม่มีพฤติกรรมที่ชัดเจนมาก:

รหัสต่อไปนี้สร้าง "ตัวอักษร"

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

อย่างไรก็ตามหากเราลบการประกาศฟังก์ชันชื่อคลาสออกจากคลาสเบต้าเราจะได้ผลลัพธ์เป็น 'alphaalpha'


1
ดีมาก. สิ่งเดียวกันนี้แสดงในคู่มือ PHP แต่จะชัดเจนกว่ามาก สำหรับการอ้างอิง: php.net/manual/en/language.oop5.late-static-bindings.php (ดูตัวอย่าง 4)
musicin3d

11

ฉันอ้างจากหนังสือ: "PHP Master write modern code"

การผูกแบบคงที่ในช่วงปลายเป็นคุณลักษณะที่นำมาใช้กับ php 5.3 ช่วยให้เราสามารถสืบทอดวิธีการแบบคงที่จากคลาสแม่และเพื่ออ้างอิงคลาสลูกที่ถูกเรียก

ซึ่งหมายความว่าคุณสามารถมีคลาสนามธรรมด้วยวิธีการแบบคงที่และอ้างอิงการใช้งานที่เป็นรูปธรรมของคลาสย่อยโดยใช้ สัญกรณ์static :: method ()แทน self :: method ()

อย่าลังเลที่จะดูเอกสาร php อย่างเป็นทางการเช่นกัน: http://php.net/manual/en/language.oop5.late-static-bindings.php


วิธีที่ชัดเจนที่สุดในการอธิบาย Late Static Binding คือตัวอย่างง่ายๆ ดูคำจำกัดความสองคลาสด้านล่างและอ่านต่อ

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";
    }
}

เราเห็นคลาสผู้ปกครอง (ยานพาหนะ) และคลาสเด็ก (รถยนต์) คลาสผู้ปกครองมี 2 วิธีการสาธารณะ:

  • invokeDriveByStatic
  • invokeStopBySelf

คลาสผู้ปกครองยังมี 2 วิธีส่วนตัว:

  • drive
  • stop

คลาสย่อยจะแทนที่ 2 วิธี:

  • drive
  • stop

ตอนนี้ขอเรียกใช้วิธีการสาธารณะ:

  • invokeDriveByStatic
  • invokeStopBySelf

ถามตัวเองว่าชั้นเรียนไหนเรียกร้องinvokeDriveByStatic/ invokeStopBySelf? ระดับผู้ปกครองหรือเด็ก?

ดูด้านล่าง:

// 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

staticคำหลักที่จะใช้ในรูปแบบการออกแบบโทน ดูลิงก์: https://refactoring.guru/design-patterns/singleton/php/example


7

ตัวอย่างที่ง่ายที่สุดเพื่อแสดงความแตกต่าง
หมายเหตุตนเอง :: $ c

class A
{
    static $c = 7;

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

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

B::getVal(); // 7

การผูกแบบคงที่ปลายหมายเหตุคง :: $ c

class A
{
    static $c = 7;

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

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

B::getVal(); // 8

4

ตัวอย่างเช่น:

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

ดูจาก "ทำไมฉันถึงใช้สิ่งนี้" มุมมองโดยพื้นฐานแล้วเป็นวิธีการเปลี่ยนบริบทซึ่งวิธีการแบบคงที่กำลังถูกตีความ / รัน

กับselfบริบทเป็นหนึ่งในสถานที่ที่คุณกำหนดวิธีการเดิม ด้วยstaticมันเป็นสิ่งที่คุณเรียกมันจาก


1

นอกจากนี้โปรดดูว่าคุณอัปเดตตัวแปรคงในคลาสย่อยหรือไม่ ฉันพบผลลัพธ์ที่ไม่คาดคิด (ค่อนข้าง) ที่เด็ก B อัปเดตลูก C:

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
// )

คุณสามารถแก้ไขได้โดยการประกาศตัวแปรเดียวกันในคลาสย่อยแต่ละคลาสเช่น

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;        
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.