2012-10-21 46 views
18

उदाहरण # 2 http://php.net/manual/en/language.oop5.traits.php राज्योंPHP विशेषता: क्या यह सुनिश्चित करने का एक उचित तरीका है कि एक विशेषता का उपयोग कर वर्ग एक सुपर क्लास को बढ़ाता है जिसमें कुछ विधि शामिल है? पीएचपी पुस्तिका से

<?php 
class Base { 
    public function sayHello() { 
     echo 'Hello '; 
    } 
} 

trait SayWorld { 
    public function sayHello() { 
     parent::sayHello(); 
     echo 'World!'; 
    } 
} 

class MyHelloWorld extends Base { 
    use SayWorld; 
} 

$o = new MyHelloWorld(); 
$o->sayHello(); 
?> 

यह सही कोड है, लेकिन यह उस संदर्भ में parent:: उपयोग करने के लिए सुरक्षित नहीं है। जब तक मैं sayHello() विधि कॉल

<?php 
class MyOwnHelloWorld 
{ 
    use SayWorld; 
} 
?> 

इस कोड को किसी भी त्रुटि का उत्पादन नहीं होगा: मान लीजिए कि मैं अपने ही 'हैलो दुनिया' वर्ग है जो किसी भी अन्य वर्गों के वारिस नहीं है लिखा करते हैं। ये गलत है।

दूसरी ओर यदि विशेषता को एक निश्चित विधि का उपयोग करने की आवश्यकता है, तो मैं इस विधि को सार के रूप में लिख सकता हूं, और यह अच्छा है क्योंकि यह सुनिश्चित करता है कि विशेषता का समय संकलन समय पर सही ढंग से उपयोग किया जाता है। लेकिन इस जनक वर्गों पर लागू नहीं होता:

<?php 
trait SayWorld 
{ 
    public function sayHelloWorld() 
    { 
     $this->sayHello(); 
     echo 'World!'; 
    } 

    public abstract function sayHello(); // compile-time safety 

} 

तो मेरे सवाल है: (रन टाइम पर नहीं संकलन समय पर,) सुनिश्चित करने के लिए एक रास्ता है कि वर्ग जो एक निश्चित विशेषता का उपयोग करता parent::sayHello() विधि होगा?

+0

आप जो कर सकते हैं वह उस पद्धति का उपयोग करके वर्ग को मजबूर करने के लिए एक सार विधि जोड़ना है जिसकी आपको आवश्यकता है। इस तरह यह वर्ग पदानुक्रम से स्वतंत्र हो जाता है (लक्षणों के पीछे विचार: पी) – Jarry

उत्तर

4

नहीं, ऐसा नहीं है। वास्तव में, यह उदाहरण बहुत बुरा है, क्योंकि लक्षणों को पेश करने का उद्देश्य विरासत पर भरोसा किए बिना कई कक्षाओं में समान कार्यक्षमता पेश करना था, और parent का उपयोग करने के लिए न केवल कक्षा के माता-पिता की आवश्यकता होती है, बल्कि इसमें विशिष्ट विधि भी होनी चाहिए।

एक तरफ नोट पर, parent कॉल संकलन समय पर चेक नहीं किए जाते हैं, आप सरल वर्ग को परिभाषित कर सकते हैं जो इसके तरीकों में अभिभावक कॉल के साथ कुछ भी नहीं बढ़ाता है, चींटी यह तब तक काम करेगी जब तक कि इनमें से किसी एक विधि को कॉल नहीं किया जाता है।

+0

इसके लिए धन्यवाद। मुझे पता है कि सरल वर्ग संकलन समय पर अभिभावक कॉल की जांच नहीं करते हैं, लेकिन यह अभी भी एक सही कोड है। मेरा हमेशा के लिए आईडीई माता-पिता कॉल का पता लगा सकता है, जिसका अर्थ है कि जब मैं PHP से एक मजबूत टाइप की गई भाषा में स्विच करता हूं तो यह अभी भी सही कोड होगा। यह मुझे रात में सोने की अनुमति देता है। लेकिन जब कई विरासत की बात आती है तो मुझे किसी अन्य भाषा से अवगत नहीं है जो ऐसा नहीं कर सकता है। स्कैला में लक्षणों की एक अवधारणा दोनों तरीकों से विरासत की अनुमति देती है। सी ++ और पायथन कक्षाएं कई 'माता-पिता' का उत्तराधिकारी हो सकती हैं। –

+0

तो मुझे लगता है कि मैं PHP सीमाओं के चारों ओर एक रास्ता देख रहा हूं जो मेरे कोड को थोड़ा और अधिक प्रकार से सुरक्षित बनाएगा। –

0

मुझे लगता है कि एक तरह से लक्षण के बिना पूरी तरह से है:

class BaseClass 
{ 
    public function sayHello() { 
      echo 'Hello '; 
    } 
} 

class SayWorld 
{ 
    protected $parent = null; 

    function __construct(BaseClass $base) { 
     $this->parent = $base; 
    } 

    public function sayHelloWorld() 
    { 
     $this->parent->sayHello(); 
     echo 'World!'; 
    } 
} 

class MyHelloWorld extends Base { 
    protected $SayWorld = null; 

    function __construct() { 
     $this->SayWorld = new SayWorld($this); 
    } 

    public function __call (string $name , array $arguments) { 
     if(method_exists($this->SayWorld, $name)) { 
      $this->SayWorld->$name(); 
     } 
    } 
} 
2

आप देख सकते हैं $ यह एक विशिष्ट वर्ग का विस्तार या एक विशिष्ट इंटरफ़ेस को लागू करता है, तो:

interface SayHelloInterface { 
    public function sayHello(); 
} 

trait SayWorldTrait { 
    public function sayHello() { 
     if (!in_array('SayHello', class_parents($this))) { 
      throw new \LogicException('SayWorldTrait may be used only in classes that extends SayHello.'); 
     } 
     if (!$this instanceof SayHelloInterface) { 
      throw new \LogicException('SayWorldTrait may be used only in classes that implements SayHelloInterface.'); 
     } 
     parent::sayHello(); 
     echo 'World!'; 
    } 
} 

class SayHello { 
    public function sayHello() { 
     echo 'Hello '; 
    } 
} 

class First extends SayHello { 
    use SayWorldTrait; 
} 

class Second implements SayHelloInterface { 
    use SayWorldTrait; 
} 

try { 
    $test = new First(); 
    $test->sayHello(); // throws logic exception because the First class does not implements SayHelloInterface 
} catch(\Exception $e) { 
    echo $e->getMessage(); 
} 

try { 
    $test = new Second(); 
    $test->sayHello(); // throws logic exception because the Second class does not extends SayHello 
} catch(\Exception $e) { 
    echo $e->getMessage(); 
} 
1

पीएचपी संकलन चरण केवल बनाता है बाईटकोड। बाकी सब कुछ रन-टाइम पर किया जाता है, जिसमें पॉलिमॉर्फिक निर्णय लेने सहित। इस प्रकार, नीचे की तरह कोड को संकलित करता है:

class A {} 
class B extends A { 
    public function __construct() { 
     parent::__construct(); 
    } 
} 

लेकिन जब run ऊपर चल रही है:

$b = new B; 

इस प्रकार आप सख्ती से संकलन समय पर जाँच parent नहीं हो सकता। सबसे अच्छा आप इसे जितना जल्दी हो सके रन-टाइम पर रोक सकते हैं। जैसा कि अन्य उत्तरों दिखाए गए हैं, instanceof के साथ अपनी विशेषता विधि के अंदर ऐसा करना संभव है। जब मैं जानता हूं कि एक विशेष विधि को किसी विशेष अनुबंध की आवश्यकता है तो मैं व्यक्तिगत रूप से टाइप-संकेत का उपयोग करना पसंद करता हूं।

यह सब लक्षणों के मौलिक उद्देश्य के लिए उबलते हैं: समय कॉपी और पेस्ट संकलित करें। बस। लक्षण अनुबंधों के बारे में कुछ नहीं जानते हैं। बहुरूपता के बारे में कुछ भी नहीं पता। वे फिर से उपयोग के लिए एक तंत्र प्रदान करते हैं। इंटरफेस के साथ मिलकर, वे काफी शक्तिशाली हैं, हालांकि कुछ हद तक वर्बोज़।

वास्तव में, first academic discussion of traits देता है विचार यह है कि लक्षण "शुद्ध" के लिए हैं, जिसमें वे उनके आसपास वस्तु का ज्ञान नहीं है नंगा:

एक विशेषता अनिवार्य रूप से शुद्ध तरीकों का एक समूह है कि कक्षाओं के लिए एक बिल्डिंग ब्लॉक के रूप में कार्य करता है और कोड पुन: उपयोग की एक आदिम इकाई है। इस मॉडल में, कक्षाएं गुणों के एक सेट से बनायी जाती हैं जो गोंद कोड निर्दिष्ट करती हैं जो गुणों को एकसाथ जोड़ती है और आवश्यक स्थिति तक पहुंचती है।

"If Traits Weren't Evil, They'd Be Funny" अच्छी तरह से अंक, नुकसान और विकल्पों को सारांशित करता है। मैं गुणों के लिए लेखक के विट्रियल को साझा नहीं करता हूं: जब मैं समझता हूं और हमेशा interface के साथ जोड़ी में होता हूं तो मैं उनका उपयोग करता हूं। PHP दस्तावेज़ में उदाहरण खराब व्यवहार को प्रोत्साहित करता है दुर्भाग्यपूर्ण है।

+1

उस समय के दौरान जब मैंने इस सवाल से पूछा तो मैंने वास्तव में लक्षणों का उपयोग बंद कर दिया। और जब भी लक्षणों को छोड़ना संभव हो, मैं अपने पुराने कोड को फिर से लिखने की कोशिश करता हूं। आप कह सकते हैं कि मैं बड़ा हुआ। वे कभी-कभी उपयोगी होते हैं लेकिन केवल कुछ ही स्थितियों में। –