การผูกแบบคงที่ใน PHP คืออะไร?
การผูกแบบคงที่ใน PHP คืออะไร?
คำตอบ:
คุณต้องอ่านLate Static Bindingsในคู่มือ PHP อย่างแน่นอน อย่างไรก็ตามฉันจะพยายามสรุปให้คุณทราบอย่างรวดเร็ว
โดยพื้นฐานแล้วมันเป็นความจริงที่ว่าself
คีย์เวิร์ดไม่เป็นไปตามกฎการสืบทอดเดียวกัน self
มักจะแก้ไขไปยังคลาสที่ใช้ ซึ่งหมายความว่าหากคุณสร้างเมธอดในคลาสแม่และเรียกใช้จากคลาสลูกself
จะไม่อ้างอิงเด็กอย่างที่คุณคาดหวัง
การผูกแบบคงที่ในช่วงปลายแนะนำการใช้งานใหม่สำหรับstatic
คำหลักซึ่งกล่าวถึงข้อบกพร่องนี้ เมื่อคุณใช้static
จะแสดงถึงคลาสที่คุณใช้เป็นครั้งแรกเช่น มัน 'ผูก' กับคลาสรันไทม์
นี่คือแนวคิดพื้นฐานสองประการที่อยู่เบื้องหลัง วิธีself
, parent
และstatic
ทำงานเมื่อstatic
อยู่ในการเล่นสามารถจะมีความซับซ้อนดังนั้นแทนที่จะไปในรายละเอียดมากขึ้นผมขอแนะนำให้คุณศึกษาตัวอย่างหน้าคู่มือ เมื่อคุณเข้าใจพื้นฐานของคำหลักแต่ละคำแล้วตัวอย่างก็ค่อนข้างจำเป็นในการดูว่าคุณจะได้ผลลัพธ์แบบใด
self
คีย์เวิร์ดไม่เป็นไปตามกฎของการสืบทอดself
จะแก้ไขเป็นคลาสที่จะใช้เสมอ" - ซึ่งไม่ได้หมายความว่าคุณไม่สามารถเรียกวิธีการแบบคงที่ของผู้ปกครองจากวัตถุลูกผ่านได้self
เช่นเดียวกับวิธีการที่ไม่คงที่ คุณอาจจะหมายถึงสิ่งที่ถูกต้อง แต่คุณควรเรียบเรียงใหม่ ทุกอย่างมีความสำคัญมากเมื่อเด็ก ๆ มีสมาชิกที่มีชื่อเหมือนกันเท่านั้นเนื่องจากคุณสามารถตัดสินใจได้ว่าจะอ้างถึงคนใดโดยใช้static::
แทน
จาก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::
แนะนำขอบเขต
ไม่มีพฤติกรรมที่ชัดเจนมาก:
รหัสต่อไปนี้สร้าง "ตัวอักษร"
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'
ฉันอ้างจากหนังสือ: "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
ตัวอย่างที่ง่ายที่สุดเพื่อแสดงความแตกต่าง
หมายเหตุตนเอง :: $ 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
ตัวอย่างเช่น:
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();
ดูจาก "ทำไมฉันถึงใช้สิ่งนี้" มุมมองโดยพื้นฐานแล้วเป็นวิธีการเปลี่ยนบริบทซึ่งวิธีการแบบคงที่กำลังถูกตีความ / รัน
กับself
บริบทเป็นหนึ่งในสถานที่ที่คุณกำหนดวิธีการเดิม ด้วยstatic
มันเป็นสิ่งที่คุณเรียกมันจาก
นอกจากนี้โปรดดูว่าคุณอัปเดตตัวแปรคงในคลาสย่อยหรือไม่ ฉันพบผลลัพธ์ที่ไม่คาดคิด (ค่อนข้าง) ที่เด็ก 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;
}
}