เพื่อขยายคำตอบของ Berry การตั้งค่าระดับการเข้าถึงเป็นแบบป้องกันจะอนุญาตให้ใช้ __get และ __set กับคุณสมบัติที่ประกาศไว้อย่างชัดเจน (อย่างน้อยเมื่อเข้าถึงนอกคลาส) และความเร็วจะช้าลงมากฉันจะเสนอความคิดเห็นจากคำถามอื่น ในหัวข้อนี้และสร้างกรณีสำหรับการใช้งานต่อไป:
ฉันยอมรับว่า __get ช้ากว่าสำหรับฟังก์ชัน get ที่กำหนดเอง (ทำสิ่งเดียวกัน) นี่คือ 0.0124455 เวลาสำหรับ __get () และ 0.0024445 นี้สำหรับ get () ที่กำหนดเองหลังจาก 10,000 ลูป - Melsi 23 พ.ย. 55 เวลา 22:32 น. แนวทางปฏิบัติที่ดีที่สุด: PHP Magic Methods __set และ __get
จากการทดสอบของ Melsi ช้ากว่ามากคือช้ากว่าประมาณ 5 เท่า นั่นช้ากว่ามาก แต่โปรดทราบว่าการทดสอบแสดงให้เห็นว่าคุณยังสามารถเข้าถึงคุณสมบัติได้ด้วยวิธีนี้ 10,000 ครั้งโดยนับเวลาสำหรับการวนซ้ำในเวลาประมาณ 1/100 วินาที มันช้ากว่ามากเมื่อเทียบกับวิธีการรับและกำหนดจริงที่กำหนดไว้และนั่นเป็นการพูดน้อย แต่ในรูปแบบที่ยิ่งใหญ่ของสิ่งต่างๆแม้จะช้ากว่า 5 เท่าก็ไม่เคยช้า
เวลาในการคำนวณของการดำเนินการยังคงน้อยมากและไม่คุ้มค่าที่จะพิจารณาใน 99% ของการใช้งานจริง ครั้งเดียวที่ควรหลีกเลี่ยงจริงๆคือเมื่อคุณกำลังจะเข้าถึงคุณสมบัติมากกว่า 10,000 ครั้งในคำขอเดียว ไซต์ที่มีการเข้าชมสูงกำลังทำสิ่งที่ผิดพลาดหากพวกเขาไม่สามารถทุ่มเซิร์ฟเวอร์เพิ่มอีกสองสามเครื่องเพื่อให้แอปพลิเคชันทำงานต่อไปได้ โฆษณาแบบข้อความบรรทัดเดียวที่ส่วนท้ายของไซต์ที่มีการเข้าชมสูงซึ่งอัตราการเข้าถึงกลายเป็นปัญหาอาจต้องจ่ายค่าฟาร์ม 1,000 เซิร์ฟเวอร์ด้วยข้อความบรรทัดนั้น ผู้ใช้ปลายทางจะไม่แตะนิ้วสงสัยว่าอะไรใช้เวลาโหลดหน้าเว็บนานขนาดนี้เนื่องจากการเข้าถึงคุณสมบัติของแอปพลิเคชันของคุณใช้เวลาหนึ่งในล้านวินาที
ฉันบอกว่าคำพูดนี้ในฐานะนักพัฒนาที่มาจากพื้นหลังใน. NET แต่วิธีการรับและตั้งค่าที่มองไม่เห็นให้กับผู้บริโภคไม่ใช่สิ่งประดิษฐ์ของ. NET พวกเขาไม่ใช่คุณสมบัติหากไม่มีพวกเขาและวิธีการวิเศษเหล่านี้เป็นพระคุณการประหยัดของนักพัฒนา PHP ที่เรียกคุณสมบัติของพวกเขาว่า "คุณสมบัติ" เลย นอกจากนี้ส่วนขยาย Visual Studio สำหรับ PHP ยังรองรับ intellisense พร้อมคุณสมบัติที่ได้รับการป้องกันด้วยเคล็ดลับนั้นฉันคิดว่า ฉันคิดว่ากับนักพัฒนาที่ใช้เมธอดมายากล __get และ __set ด้วยวิธีนี้นักพัฒนา PHP จะปรับเวลาการดำเนินการเพื่อตอบสนองชุมชนนักพัฒนา
แก้ไข: ในทางทฤษฎีคุณสมบัติที่ได้รับการป้องกันดูเหมือนว่าจะใช้ได้ในสถานการณ์ส่วนใหญ่ ในทางปฏิบัติปรากฎว่ามีหลายครั้งที่คุณต้องการใช้ getters และ setters เมื่อเข้าถึงคุณสมบัติภายในนิยามคลาสและคลาสเพิ่มเติม ทางออกที่ดีกว่าคือคลาสพื้นฐานและอินเทอร์เฟซสำหรับการขยายคลาสอื่น ๆ ดังนั้นคุณสามารถคัดลอกโค้ดสองสามบรรทัดจากคลาสพื้นฐานไปยังคลาสที่ใช้งานได้ ฉันกำลังทำเพิ่มอีกเล็กน้อยกับคลาสพื้นฐานของโปรเจ็กต์ดังนั้นฉันจึงไม่มีอินเทอร์เฟซที่จะให้ในตอนนี้ แต่นี่คือนิยามคลาสที่ยังไม่ผ่านการทดสอบพร้อมคุณสมบัติเวทย์มนตร์การรับและการตั้งค่าโดยใช้การสะท้อนเพื่อลบและย้ายคุณสมบัติไปที่ อาร์เรย์ที่ได้รับการป้องกัน:
class Component {
protected $properties = array();
public function __get($name) {
$caller = array_shift(debug_backtrace());
$max_access = ReflectionProperty::IS_PUBLIC;
if (is_subclass_of($caller['class'], get_class($this)))
$max_access = ReflectionProperty::IS_PROTECTED;
if ($caller['class'] == get_class($this))
$max_access = ReflectionProperty::IS_PRIVATE;
if (!empty($this->properties[$name])
&& $this->properties[$name]->class == get_class()
&& $this->properties[$name]->access <= $max_access)
switch ($name) {
default:
return $this->properties[$name]->value;
}
}
public function __set($name, $value) {
$caller = array_shift(debug_backtrace());
$max_access = ReflectionProperty::IS_PUBLIC;
if (is_subclass_of($caller['class'], get_class($this)))
$max_access = ReflectionProperty::IS_PROTECTED;
if ($caller['class'] == get_class($this))
$max_access = ReflectionProperty::IS_PRIVATE;
if (!empty($this->properties[$name])
&& $this->properties[$name]->class == get_class()
&& $this->properties[$name]->access <= $max_access)
switch ($name) {
default:
$this->properties[$name]->value = $value;
}
}
function __construct() {
$reflected_class = new ReflectionClass($this);
$properties = array();
foreach ($reflected_class->getProperties() as $property) {
if ($property->isStatic()) { continue; }
$properties[$property->name] = (object)array(
'name' => $property->name, 'value' => $property->value
, 'access' => $property->getModifier(), 'class' => get_class($this));
unset($this->{$property->name}); }
$this->properties = $properties;
}
}
ขออภัยหากมีข้อบกพร่องในโค้ด