การประกาศฟิลด์ในคลาสจริง ๆ แล้วเป็นอันตรายใน PHP หรือไม่


13

พิจารณาโค้ดต่อไปนี้ซึ่งตัวตั้งค่าใช้งานไม่ได้เนื่องจากเจตนาผิดพลาดในการตั้งโปรแกรมแบบธรรมดาที่ฉันเคยทำมาแล้วสองสามครั้งในอดีต:

<?php

    class TestClass {

        private $testField;

        function setField($newVal) {
            $testField = $newVal;
            // deliberately broken; should be `$this->testField = $newVal`
        }

        function getField() {
            return $this->testField;
        }

    }

    $testInstance = new TestClass();
    $testInstance->setField("Hello world!");

    // Actually prints nothing; getField() returns null
    echo $testInstance->getField(); 

?>

ความจริงที่ฉันประกาศ$testFieldที่ด้านบนของชั้นเรียนช่วยปกปิดข้อผิดพลาดในการเขียนโปรแกรมจากฉัน หากฉันไม่ได้ประกาศเขตข้อมูลฉันจะได้รับข้อความคล้ายกับคำเตือนต่อไปนี้ที่พิมพ์ลงในบันทึกข้อผิดพลาดของฉันเมื่อเรียกสคริปต์นี้ซึ่งอาจเป็นประโยชน์ในการช่วยแก้ไขข้อบกพร่องของฉัน - โดยเฉพาะอย่างยิ่งถ้าฉันทำข้อผิดพลาดเช่นนี้ แอปพลิเคชันในโลกแห่งความจริงที่มีขนาดใหญ่และซับซ้อน:

ประกาศ PHP: คุณสมบัติที่ไม่ได้กำหนด: TestClass :: $ testField ใน /var/www/test.php ที่บรรทัดที่ 13

ด้วยการประกาศไม่มีคำเตือน

บางทีฉันหายไปบางอย่าง แต่ฉันรู้เพียงสองเหตุผลที่จะประกาศฟิลด์คลาสใน PHP: ประการแรกการประกาศทำหน้าที่เป็นเอกสารประกอบและประการที่สองโดยไม่มีการประกาศเราไม่สามารถใช้privateและprotectedตัวดัดแปลงการเข้าถึงซึ่งเป็น มีประโยชน์เนื้อหา เนื่องจากอาร์กิวเมนต์หลังไม่ได้ใช้กับเขตข้อมูลสาธารณะ - การกำหนดให้กับเขตข้อมูลที่ไม่ได้ประกาศของวัตถุทำให้เป็นสาธารณะ - ฉันคิดว่าอย่างน้อยฉันควรจะแสดงความคิดเห็นเกี่ยวกับการประกาศเขตข้อมูลสาธารณะทั้งหมดของฉัน ความคิดเห็นจะให้ค่าเอกสารที่แน่นอนเหมือนกัน แต่ฉันจะได้รับประโยชน์จากคำเตือนหากฉันพยายามอ่านฟิลด์ที่ไม่มีการกำหนดค่าเริ่มต้น

อย่างไรก็ตามเมื่อพิจารณาเพิ่มเติมแล้วดูเหมือนว่ามันไม่สมเหตุสมผลเลยที่จะหยุดอยู่แค่นั้น เนื่องจากในประสบการณ์ของฉันพยายามอ่านฟิลด์ uninitialized เป็นสาเหตุของข้อผิดพลาดทั่วไปมากกว่าพยายามอ่านหรือปรับเปลี่ยนฟิลด์ส่วนตัวหรือป้องกันอย่างไม่เหมาะสม (ฉันเคยทำมาหลายครั้งแล้วในอาชีพการเขียนโปรแกรมระยะสั้นของฉัน แต่ไม่เคยหลัง ) ดูเหมือนว่าฉันชอบที่จะแสดงความคิดเห็นการประกาศภาคสนามทั้งหมด - ไม่ใช่แค่การเปิดเผยต่อสาธารณะ - เป็นการปฏิบัติที่ดี

สิ่งที่ทำให้ฉันลังเลคือฉันไม่เคยเห็นใครทำในรหัส ทำไมจะไม่ล่ะ? มีประโยชน์ในการประกาศฟิลด์คลาสที่ฉันไม่ทราบหรือไม่? หรือฉันสามารถแก้ไขการกำหนดค่าของ PHP ในบางวิธีเพื่อเปลี่ยนพฤติกรรมของการประกาศฟิลด์เพื่อให้ฉันสามารถใช้การประกาศฟิลด์จริงและยังคงได้รับประโยชน์จากคำเตือน "คุณสมบัติที่ไม่ได้กำหนด"? หรือมีอะไรอีกที่ฉันไม่ได้รับในการวิเคราะห์ของฉัน?


1
เนื้อหามีประโยชน์หรือไม่ ประโยชน์ที่คุณระบุมีความสำคัญอย่างยิ่ง ฉันอาจจะปฏิเสธที่จะทำงานบนโค้ดที่ไม่มีการประกาศคุณสมบัติอย่างชัดเจน
Michael

2
จริงๆแล้ววิธีในการป้องกันตัวเองจากข้อผิดพลาดคือการตรวจสอบข้อผิดพลาดอย่างระมัดระวังและดีกว่าผ่านการทดสอบหน่วย
Michael

1
มีการรายงานข้อผิดพลาด php ในตัว (ระดับการแจ้งเตือน) ที่จะบอกคุณว่าคุณใช้ตัวแปรโดยไม่ต้องแจ้งให้ทราบก่อน
Crayon Violent

3
@MarkAmery ฉันจะคิดว่าการเริ่มต้นเมามันรวดเร็วเป็นหนึ่งในสถานที่ที่สำคัญที่สุดที่จะนำมาใช้ทดสอบหน่วยที่เข้มงวด - ตั้งแต่คุณเปลี่ยนรหัสเสมอ, คุณจะเสมอหมดมัน นั่นคือจุดประสงค์ที่แท้จริงของการทดสอบที่เข้มงวดและการเลิกเล่น TDD ใช่ฉันเดาว่าการใช้เครื่องหมายขีดล่างอาจช่วยให้คุณจำได้ว่าคุณกำลังเข้าถึงสิ่งส่วนตัว แต่สำหรับฉันแล้วความคิดของการใช้มาตรฐานการเข้ารหัสเฉพาะเพื่อปกป้องฉันจากการทำผิดพลาดที่ฉันไม่ควรทำนั้นไม่มั่นคง ชอบทำTRUE === $variableเพื่อป้องกันตัวเองจากการมอบหมายโดยไม่ได้ตั้งใจแทนที่จะเปรียบเทียบ
ไมเคิล

1
@MarkAmery โปรดทราบว่าคีย์เวิร์ดการมองเห็นถูกวิเคราะห์โดยเครื่องมือเอกสารอัตโนมัติดังนั้นพวกเขาจึงให้ "คุณค่าของเอกสาร" มากกว่าความคิดเห็นที่คุณจะใส่ด้วยตนเอง
ไมเคิล

คำตอบ:


15

คุณควรประกาศคุณสมบัติคลาสของคุณล่วงหน้า ในขณะที่ PHP เป็นภาษาแบบไดนามิกและมีความสุขไปพร้อมกับคุณสร้างคุณสมบัติของคุณที่รันไทม์มีข้อเสียหลายเส้นทางนี้

  • คอมไพเลอร์สามารถปรับคุณสมบัติประกาศให้เหมาะสม เมื่อคุณประกาศคุณสมบัติแบบไดนามิกนี่คือประสิทธิภาพการทำงานที่คอมไพเลอร์ต้องสร้างตารางแฮชแบบไดนามิกเพื่อจัดเก็บคุณสมบัติแบบไดนามิกของคุณ
  • ฉันไม่ได้ 100% ในอันนี้ แต่ฉันเชื่อว่าเครื่องมือเพิ่มประสิทธิภาพ bytecode เช่น APC จะไม่เป็นประโยชน์เพราะพวกเขาจะไม่มีภาพเต็มรูปแบบในชั้นเรียนของคุณ (และเครื่องมือเพิ่มประสิทธิภาพอย่าง APC เป็นสิ่งที่จำเป็น )
  • ทำให้โค้ดของคุณอ่านยากขึ้น 1000x คนจะเกลียดคุณ
  • ทำให้มีความเป็นไปได้มากกว่าที่คุณจะทำผิดพลาด 1,000 เท่า (เป็น getId หรือ getID หรือไม่รอคุณใช้ทั้งสองอย่างล้มเหลว)
  • ไม่มีการเติมข้อความอัตโนมัติ IDE หรือพิมพ์คำใบ้
  • เครื่องกำเนิดเอกสารจะไม่เห็นคุณสมบัติของคุณ

ปัญหาที่คุณอธิบายเป็นจริงรองลงมาเมื่อเปรียบเทียบกับปัญหาที่ไม่ได้ประกาศคุณสมบัติของคุณในการกำหนดชั้นเรียนของคุณ นี่เป็นทางออกที่ดี

รับใช้เพื่อประกาศค่าเริ่มต้นสำหรับคุณสมบัติของคุณ

private $testField = null;
private $testField = '';
private $testField = 0;
private $testField = []; //array()
private $testField = false;

ยกเว้นคุณสมบัติที่จะจัดเก็บวัตถุสิ่งนี้จะครอบคลุมประเภทฐานส่วนใหญ่ที่คุณจะจัดเก็บ คุณสมบัติที่จะจัดเก็บวัตถุสามารถตั้งค่าในตัวสร้างของคุณ

กฎที่ดีสำหรับการออกแบบคลาสคือหลังจากที่วัตถุของคุณถูกสร้างขึ้นและคอนสตรัคเตอร์ของคุณทำงานแล้วคุณไม่ควรมีคุณสมบัติใด ๆ


ในการตอบสนองข้อเสีย 5 ข้อของคุณ: 1 (ประสิทธิภาพ): คุณมีที่มาสำหรับสิ่งนี้หรือไม่? 2 (ความสามารถในการอ่าน): ไม่แน่ใจว่าฉันเข้าใจ; ข้อเสนอนี้มีไว้สำหรับการแสดงความคิดเห็นการประกาศไม่ใช่แค่ลบออกดังนั้นการอ่านที่หายไปคืออะไร การเน้นไวยากรณ์ที่เป็นมิตรน้อยกว่าเล็กน้อยและความยากลำบากที่อาจเกิดขึ้นแตกต่างจากความคิดเห็นข้างเคียงฉันเดาใช่ไหม 3: อันนี้ฉันไม่เข้าใจเลย; คุณสามารถอธิบายได้ไหม 4 (IDEs): ยุติธรรมเพียงพอ - ฉันไม่มีประสบการณ์ในการเขียนโค้ด PHP ด้วย IDE และไม่รู้เกี่ยวกับคำใบ้ประเภทของ Eclipse 5 (ตัวกำเนิดเอกสาร): ยุติธรรมเพียงพอ - ไม่เคยใช้อย่างใดอย่างหนึ่ง
Mark Amery

ฉันไม่เห็นบรรทัดของคุณเกี่ยวกับการแสดงความคิดเห็น โดยไม่คำนึงถึงประเด็นข้างต้นยังคงมีผลบังคับใช้ - คุณจะรู้ได้อย่างไรว่าประเด็นใดที่ใช้งานอยู่หรือแสดงความคิดเห็นอย่างถูกต้องตามกฎหมาย?
Jarrod Nettles

เพื่อตอบสนองต่อข้อเสนอของคุณ: นี่คือสิ่งที่ฉันต้องการหลีกเลี่ยง - การกำหนดค่าเริ่มต้นแม้ในกรณีที่ไม่มีความหมายและไม่ควรใช้ค่าเริ่มต้น ปัญหาเกี่ยวกับค่าเริ่มต้นเหล่านี้ (และด้วยการประกาศโดยไม่ได้มอบหมายซึ่งเพิ่งกำหนดค่า Null) คือถ้าหากเกิดข้อผิดพลาดในการเขียนโปรแกรมฉันไม่ได้กำหนดค่าให้กับบางสิ่งในตัวสร้างเมื่อฉันต้องการแล้วแทนที่จะเป็น PHP เตือนเมื่อฉันพยายามใช้ค่านั้นในภายหลัง - ช่วยให้ฉันเห็นข้อผิดพลาดของฉัน - ทุกอย่างดูเหมือนจะทำงานได้ดีแม้ว่าชั้นเรียนจะพัง
Mark Amery

2
@ MarkAmery ความผิดพลาดในการเขียนโปรแกรมของคุณเป็นสิ่งสำคัญในการพิมพ์ผิด เราทุกคนมีพวกเขา - แต่คุณกำลังพยายามจุดชนวนระเบิดเพื่อฆ่าแมลงวันที่นี่
Jarrod Nettles

คุณอาจจะถูก ฉันใช้เวลาสองสามชั่วโมงในการติดตามข้อผิดพลาดในวันนี้ซึ่งดูเหมือนจะเกิดจากการพิมพ์ผิดทั้งหมดและรู้สึกท้อแท้จากการตระหนักรู้อย่างฉับพลันว่าถ้าฉันไม่ได้ใช้การประกาศภาคสนามฉันจะได้รับการแจ้งเตือนและ รู้ได้ทันทีว่าข้อผิดพลาดของฉันอยู่ที่ใด (ซึ่งฉันคิดเสมอว่าจะเกิดขึ้นในสถานการณ์เหล่านี้ต่อไป; ฉันไม่ได้ตระหนักถึงการประกาศกำหนดเขตข้อมูลให้เป็นโมฆะ) ความสามารถในการเข้าถึงได้ทันทีของประสบการณ์นั้นอาจทำให้ฉันตัดสินว่ามันมีแนวโน้มที่จะเกิดขึ้นอีกหรือไม่คุ้มค่าที่จะป้องกัน
Mark Amery

2

ฉันทำงานกับโค้ดบางอย่างที่ใช้คุณสมบัติวัตถุที่สร้างขึ้นแบบไดนามิก ฉันคิดว่าการใช้คุณสมบัติวัตถุที่สร้างขึ้นแบบไดนามิกนั้นค่อนข้างดี (จริงในความคิดของฉัน) อย่างไรก็ตามโปรแกรมของฉันใช้เวลา 7 วินาทีในการทำงาน ฉันลบคุณสมบัติวัตถุแบบไดนามิกและแทนที่พวกเขาคุณสมบัติวัตถุที่ประกาศเป็นส่วนหนึ่งของแต่ละคลาส (สาธารณะในกรณีนี้) เวลา CPU เพิ่มขึ้นจาก 7 วินาทีเป็น 0.177 วินาที นั่นเป็นเรื่องสำคัญมาก

เป็นไปได้ว่าฉันทำสิ่งผิดปกติในลักษณะที่ฉันใช้คุณสมบัติวัตถุแบบไดนามิก อาจเป็นไปได้ว่าการกำหนดค่าของฉันใช้งานไม่ได้ แน่นอนฉันควรจะบอกว่าฉันมีการกำหนดค่า PHP วานิลลาธรรมดามากในเครื่องของฉัน

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