เป็นเรื่องยาวที่น่าเศร้า
เมื่อ PHP 5.2 เปิดตัวคำเตือนนี้เป็นครั้งแรกการผูกแบบคงที่ล่าช้ายังไม่ได้อยู่ในภาษา ในกรณีที่คุณไม่คุ้นเคยกับการผูกแบบคงที่ในช่วงปลายโปรดทราบว่ารหัสแบบนี้ไม่ได้ผลอย่างที่คุณคาดหวัง:
<?php
abstract class ParentClass {
static function foo() {
echo "I'm gonna do bar()";
self::bar();
}
abstract static function bar();
}
class ChildClass extends ParentClass {
static function bar() {
echo "Hello, World!";
}
}
ChildClass::foo();
ยกเว้นคำเตือนโหมดเข้มงวดโค้ดด้านบนใช้ไม่ได้ การself::bar()
เรียกในfoo()
อย่างชัดเจนหมายถึงbar()
วิธีการParentClass
แม้ว่าfoo()
จะถูกเรียกว่าเป็นวิธีการChildClass
ก็ตาม หากคุณพยายามรันโค้ดนี้โดยปิดโหมดเข้มงวดคุณจะเห็น " PHP Fatal error: Can not call abstract method ParentClass :: bar () "
ด้วยวิธีนี้วิธีการคงที่แบบนามธรรมใน PHP 5.2 จึงไร้ประโยชน์ จุดทั้งหมดของการใช้วิธีนามธรรมคือที่คุณสามารถเขียนโค้ดที่เรียกวิธีโดยไม่ทราบว่าสิ่งที่ดำเนินการก็จะถูกเรียก - แล้วให้การใช้งานที่แตกต่างกันในชั้นเรียนของเด็กที่แตกต่างกัน แต่เนื่องจาก PHP 5.2 ไม่มีวิธีที่สะอาดในการเขียนเมธอดของคลาสพาเรนต์ที่เรียกเมธอดแบบคงที่ของคลาสลูกที่เรียกว่าการใช้เมธอดแบบคงที่นามธรรมนี้จึงไม่สามารถทำได้ ดังนั้นการใช้งานใด ๆabstract static
ใน PHP 5.2 จึงเป็นโค้ดที่ไม่ถูกต้องอาจได้รับแรงบันดาลใจจากความเข้าใจผิดว่าself
คำหลักทำงานอย่างไร มันสมเหตุสมผลอย่างยิ่งที่จะต้องเตือนเรื่องนี้
แต่จากนั้น PHP 5.3 ก็เข้ามาพร้อมกับความสามารถในการอ้างถึงคลาสที่เมธอดถูกเรียกใช้ผ่านstatic
คีย์เวิร์ด (ไม่เหมือนกับself
คีย์เวิร์ดซึ่งหมายถึงคลาสที่กำหนดเมธอดไว้เสมอ) หากคุณเปลี่ยนself::bar()
เป็นstatic::bar()
ในตัวอย่างของฉันข้างต้นมันทำงานได้ดีใน PHP 5.3 ขึ้นไป คุณสามารถอ่านเพิ่มเติมเกี่ยวกับการself
เทียบกับstatic
ที่ตัวเองใหม่กับแบบคงที่ใหม่
เมื่อเพิ่มคีย์เวิร์ดแบบคงที่อาร์กิวเมนต์ที่ชัดเจนสำหรับการabstract static
ส่งคำเตือนก็หายไป จุดประสงค์หลักของการโยงแบบคงที่ในช่วงปลายคือเพื่อให้เมธอดที่กำหนดไว้ในคลาสพาเรนต์เรียกเมธอดแบบคงที่ซึ่งจะกำหนดไว้ในคลาสย่อย การอนุญาตให้วิธีการคงที่แบบนามธรรมดูสมเหตุสมผลและสอดคล้องกันเมื่อมีการเชื่อมแบบคงที่ในช่วงปลาย
คุณยังสามารถฉันเดาว่าสร้างกรณีเพื่อรักษาคำเตือน ตัวอย่างเช่นคุณสามารถโต้แย้งได้ว่าเนื่องจาก PHP ช่วยให้คุณสามารถเรียกวิธีการแบบคงที่ของคลาสนามธรรมได้ในตัวอย่างของฉันด้านบน (แม้ว่าจะแก้ไขโดยการแทนที่self
ด้วยstatic
) คุณกำลังเปิดเผยวิธีการสาธารณะParentClass::foo()
ที่เสียและคุณไม่ต้องการจริงๆ เปิดเผย การใช้คลาสที่ไม่คงที่นั่นคือการสร้างวิธีการอินสแตนซ์เมธอดทั้งหมดและทำให้เด็ก ๆParentClass
ทั้งหมดเป็นซิงเกิลตันหรืออะไรบางอย่าง - จะแก้ปัญหานี้ได้เนื่องจากParentClass
เป็นนามธรรมไม่สามารถสร้างอินสแตนซ์ได้ดังนั้นวิธีการอินสแตนซ์จึงไม่สามารถทำได้ ถูกเรียก. ฉันคิดว่าข้อโต้แย้งนี้อ่อนแอ (เพราะฉันคิดว่าการเปิดเผยParentClass::foo()
ไม่ใช่เรื่องใหญ่และการใช้เสื้อกล้ามแทนที่จะเป็นคลาสแบบคงที่มักจะใช้คำฟุ่มเฟือยและน่าเกลียดโดยไม่จำเป็น) แต่คุณอาจไม่เห็นด้วยพอสมควร - เป็นการเรียกแบบส่วนตัว
จากข้อโต้แย้งนี้นักพัฒนา PHP ยังคงคำเตือนเป็นภาษาใช่ไหม?
เอ่อ, ไม่ตรง
รายงานข้อบกพร่องของ PHP 53081 ที่เชื่อมโยงด้านบนเรียกร้องให้ยกเลิกการแจ้งเตือนเนื่องจากการเพิ่มstatic::foo()
โครงสร้างทำให้วิธีการคงที่เป็นนามธรรมมีความสมเหตุสมผลและเป็นประโยชน์ Rasmus Lerdorf (ผู้สร้าง PHP) เริ่มต้นด้วยการติดฉลากคำขอว่าเป็นของปลอมและใช้เหตุผลที่ไม่ดีเป็นห่วงโซ่ยาวเพื่อพยายามพิสูจน์คำเตือน จากนั้นในที่สุดการแลกเปลี่ยนนี้จะเกิดขึ้น:
Giorgio
ฉันรู้ แต่:
abstract class cA
{
//static function A(){self::B();} error, undefined method
static function A(){static::B();} // good
abstract static function B();
}
class cB extends cA
{
static function B(){echo "ok";}
}
cB::A();
ราสมูส
ถูกต้องนั่นคือวิธีการทำงาน
Giorgio
แต่ไม่อนุญาต :(
ราสมูส
อะไรไม่ได้รับอนุญาต
abstract class cA {
static function A(){static::B();}
abstract static function B();
}
class cB extends cA {
static function B(){echo "ok";}
}
cB::A();
ใช้งานได้ดี เห็นได้ชัดว่าคุณไม่สามารถเรียกตัวเองว่า :: B () ได้ แต่คงที่ :: B () ก็ใช้ได้
คำกล่าวอ้างของ Rasmus ว่าโค้ดในตัวอย่าง "ใช้ได้ดี" เป็นเท็จ ดังที่คุณทราบระบบจะแสดงคำเตือนโหมดเข้มงวด ฉันเดาว่าเขากำลังทดสอบโดยไม่เปิดโหมดเข้มงวด อย่างไรก็ตาม Rasmus ที่สับสนปล่อยให้คำขอปิดโดยไม่ถูกต้องว่าเป็น "ปลอม"
และนั่นคือสาเหตุที่คำเตือนยังคงเป็นภาษา นี่อาจไม่ใช่คำอธิบายที่น่าพึงพอใจทั้งหมด - คุณอาจมาที่นี่โดยหวังว่าจะมีคำเตือนที่สมเหตุสมผล น่าเสียดายที่ในโลกแห่งความเป็นจริงบางครั้งการเลือกเกิดจากความผิดพลาดทางโลกและการใช้เหตุผลที่ไม่ดีแทนที่จะมาจากการตัดสินใจอย่างมีเหตุผล นี่เป็นเพียงหนึ่งในครั้งนั้น
โชคดีที่นับถือ Nikita โปปอฟได้ลบออกคำเตือนจากภาษา PHP 7 เป็นส่วนหนึ่งของPHP RFC: ประกาศจัดกลุ่มใหม่ ในที่สุดสติก็มีชัยแล้วและเมื่อ PHP 7 เปิดตัวเราทุกคนก็สามารถใช้งานได้อย่างมีความสุขabstract static
โดยไม่ได้รับคำเตือนที่ไร้สาระนี้