क्यों PHP Trait इंटरफेस को लागू नहीं कर सकते?


83

मैं सोच रहा हूँ क्यों PHP Trait (PHP 5.4) इंटरफेस को लागू नहीं कर सकते।

User1460043 के उत्तर से अद्यतन => ... वर्ग की आवश्यकता नहीं हो सकती है जो इसे एक विशिष्ट इंटरफ़ेस को लागू करने के लिए उपयोग करता है

मैं समझता हूं कि यह स्पष्ट हो सकता है, क्योंकि लोग सोच सकते हैं कि यदि कोई Class Aऐसा उपयोग कर रहा है Trait Tजो अप्रत्यक्ष रूप से लागू होना चाहिए interface I, (और यह सच नहीं है क्योंकि यह लक्षण बदल सकता है)।Class Ainterface IClass A

मेरे मामले में, मेरी विशेषता इंटरफ़ेस से उन तरीकों को बुला रही है जो वर्ग गुणन का उपयोग करते हैं।

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



13
यह बात नहीं है, मैं लक्षण और इंटरफेस के बीच का अंतर जानता हूं।
Leto

1
शायद कोई तकनीकी कारण है लेकिन मुझे आश्चर्य है कि आप क्यों करना चाहेंगे? आप किसी विशेषता को तुरंत नहीं कर सकते हैं, इसलिए यह एक इंटरफ़ेस लागू करने से आपको कोई टाइपिंग लाभ नहीं मिलता है। यदि आप ऐसा चाहते हैं, तो जैसा कि आप कहते हैं, उन वर्गों को बाध्य करने के लिए जो एक इंटरफ़ेस को लागू करने के लिए विशेषता का उपयोग करते हैं तो आपको आश्चर्य होता है कि क्या एक (सार) आधार वर्ग अधिक उपयुक्त होगा।

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

2
या शायद सरल शब्दों में: क्यों PHP में लक्षण प्रकार नहीं हैं?
nnvala

जवाबों:


97

वास्तव में छोटा संस्करण सरल है क्योंकि आप नहीं कर सकते। यही नहीं ट्रिट्स काम करते हैं।

जब आप use SomeTrait;PHP में लिखते हैं तो आप (प्रभावी रूप से) संकलक को उस वर्ग में ट्रेट से कोड को कॉपी और पेस्ट करने के लिए कह रहे हैं जहां इसका उपयोग किया जा रहा है।

क्योंकि वह use SomeTrait;कक्षा के अंदर है implements SomeInterface, इसलिए वह कक्षा में नहीं जुड़ सकता , क्योंकि उसे कक्षा के बाहर रहना पड़ता है।

"क्यों PHP में लक्षण टाइप नहीं हैं?"

क्योंकि वे तात्कालिक नहीं हो सकते। लक्षण वास्तव में सिर्फ एक भाषा निर्माण (इस वर्ग में गुण कोड को कॉपी और पेस्ट करने के लिए कहकर) एक वस्तु या प्रकार के विपरीत है जिसे आपके कोड द्वारा संदर्भित किया जा सकता है।

इसलिए, मैं कोड में "डिज़ाइन" करना चाहता हूं जो कि मेरी विशेषता का उपयोग करने वाले प्रत्येक वर्ग को इंटरफ़ेस को लागू करना है।

यह एक अमूर्त वर्ग का उपयोग कर useविशेषता के लिए लागू किया जा सकता है और फिर उसमें से कक्षाओं का विस्तार किया जा सकता है।

interface SomeInterface{
    public function someInterfaceFunction();
}

trait SomeTrait {
    function sayHello(){
        echo "Hello my secret is ".static::$secret;
    }
}

abstract class AbstractClass implements SomeInterface{
    use SomeTrait;
}

class TestClass extends AbstractClass {
    static public  $secret = 12345;

    //function someInterfaceFunction(){
        //Trying to instantiate this class without this function uncommented will throw an error
        //Fatal error: Class TestClass contains 1 abstract method and must therefore be 
        //declared abstract or implement the remaining methods (SomeInterface::doSomething)
    //}
}

$test = new TestClass();

$test->sayHello();

हालाँकि - यदि आपको यह लागू करने की आवश्यकता है कि कोई भी वर्ग जो Trait का उपयोग करता है, उसकी एक विशेष विधि है, तो मुझे लगता है कि आप उन लक्षणों का उपयोग कर रहे होंगे, जहाँ आपको पहली बार में अमूर्त वर्ग होना चाहिए था।

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

संपादित करें

वास्तव में आप विधि को लागू करने के लिए एक वर्ग को मजबूर करने के लिए लक्षण के अंदर सार कार्यों को परिभाषित कर सकते हैं। जैसे

trait LoggerTrait {

    public function debug($message, array $context = array()) {
        $this->log('debug', $message, $context);
    }

    abstract public function log($level, $message, array $context = array());
}

हालाँकि यह अभी भी आपको विशेषता को इंटरफ़ेस में लागू करने की अनुमति नहीं देता है, और फिर भी एक खराब डिज़ाइन की तरह बदबू आ रही है, क्योंकि इंटरफेस एक अनुबंध को परिभाषित करने में लक्षण से बेहतर है जो एक वर्ग को पूरा करने की आवश्यकता है।


2
आप इसे कैसे निर्धारित करने का सुझाव देंगे, मेरे पास एक मानव वर्ग है, यह वर्ग अय्यूब के आधार पर उपवर्गों में सारगर्भित है, लेकिन इनमें से कई नौकरियों में ऐसी विशेषताएं हैं जो साझा कोड के साथ सबसे अच्छी तरह से कार्यान्वित की जाती हैं (उदाहरण के लिए एक सचिव और प्रोग्रामर दोनों को typeविधि की आवश्यकता है )। क्या आप सोच सकते हैं कि बिना लक्षणों के इसे कैसे लागू किया जा सकता है?
स्क्रैगर

@ सागर आपको यह पूछना चाहिए कि programmers.stackexchange.com पर, लेकिन संक्षिप्त संस्करण यह है कि मैं 'ह्यूमन' को मल्टीपल 'जॉब्स' के साथ 'वर्कहोमन' क्लास बनाना चाहूंगा।
डैनैक

1
एक और। यदि इंटरफ़ेस कुछ जागरूकता अनुबंध को परिभाषित करता है और यह अनुबंध अधिकांश कार्यान्वयन के लिए सामान्य है। लेकिन उन कार्यान्वयनों के अपने प्रकार तीन हैं। कंटेनरवेयर के साथ कमांड जैसा कुछ। लेकिन कॉमन के उपयोग के अपने विशिष्ट क्षेत्र हैं। इसलिए मुझे हर बार अपने आप को दोहराने की आवश्यकता है मुझे कंटेनर जागरूकता की आवश्यकता है लेकिन यदि मैं ट्रेट का उपयोग करता हूं तो मैं विशिष्ट इंटरफ़ेस के लिए अपने अनुबंध को परिभाषित नहीं कर सकता। हो सकता है कि कोर डेवलपर्स को गो-टाइप इंटरफेस (जैसे स्ट्रक्चरल टाइपिंग) पर विचार करना चाहिए?
lazcommit

3
यह वास्तव में अजीब है, क्योंकि वास्तव में मेरे सहकर्मी और मैं कभी भी लक्षण का उपयोग करते हैं जब हम एक इंटरफ़ेस लागू करने वाले कई वर्गों में आवश्यक कोड साझा करना चाहते हैं, लेकिन विभिन्न पूर्वजों से आते हैं। यह भी कोई उचित व्याख्या नहीं है कि संकलक कोड को वर्ग के अंदर बदल सकता है लेकिन इस वर्ग द्वारा लागू किए गए इंटरफेस को नहीं। ... यह केवल एक "लापता" सुविधा है ... "क्योंकि आप नहीं कर सकते हैं" यह सबसे अच्छा समझाता है
ग्रीष्मकालीन-स्काई

5
मेरा मानना ​​है कि PHP कोर डेवलपर्स को स्काला का थोड़ा अध्ययन करना चाहिए, जहां लक्षण पूर्ण प्रकार के माने जाते हैं ... मुझे यह दुखद लगता है कि पीएचपी धीरे-धीरे अपने टाइपिंग सिस्टम में सुधार करना चाहता है, लेकिन मौजूदा अच्छी तरह से काम करने वाले कार्यान्वयन को ध्यान में नहीं
रखता है

28

वहाँ एक आरएफसी है: इंटरफेस के साथ लक्षण भाषा में जोड़े जाने के लिए निम्नलिखित सुझाव देते हैं:

trait SearchItem implements SearchItemInterface
{
    ...
}

इंटरफ़ेस द्वारा आवश्यक तरीके या तो विशेषता द्वारा कार्यान्वित किए जा सकते हैं, या सार के रूप में घोषित किए जा सकते हैं, जिस स्थिति में यह अपेक्षा की जाती है कि वह वर्ग जो इसे लागू करता है।

यह सुविधा वर्तमान में भाषा द्वारा समर्थित नहीं है, लेकिन यह विचाराधीन है (RFC की वर्तमान स्थिति है: चर्चा के तहत )।


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

लक्षणों का एक महान अनुप्रयोग एक इंटरफ़ेस का आसान-से-पेस्ट डिफ़ॉल्ट कार्यान्वयन प्रदान कर रहा है। यदि आप यह सुनिश्चित करना चाहते हैं कि एक विशेषता एक इंटरफ़ेस को पूरा करती है तो संकलक की मदद करना अच्छा होगा
शक्तिशाली क्रिस

यह प्रस्ताव ऐसा नहीं करता है ताकि किसी विशेषता का उपयोग करने वाला वर्ग स्वचालित रूप से उन लक्षणों इंटरफेस को लागू कर सके (जो कि आपके द्वारा नाम बदलने / बदलने के तरीकों को बदलने के बाद काम नहीं करेंगे)। फिसलन ढलान तर्क है कि इसे पास करने से किसी भी तरह से अधिक आक्रामक भविष्य बीत जाएगा आरएफसी को पानी नहीं रखना चाहिए
ताकतवर क्रिस

मुझे लगता है, केवल लक्षण मौजूद होने चाहिए, न ही इंटरफेस, न ही अमूर्त वर्ग। और लक्षण भाषा में टाइप होने चाहिए।
दाविद बिरनो

10

[...] कोड में "डिजाइन" करने के लिए कि हर वर्ग जो मेरे गुण का उपयोग करना चाहते हैं, उन्हें इंटरफ़ेस को लागू करना होगा। यह ट्रिट इंटरफ़ेस द्वारा परिभाषित वर्ग विधियों का उपयोग करने की अनुमति देगा और सुनिश्चित करेगा कि वे कक्षा में मौजूद हैं।

यह बहुत उचित लगता है और मैं यह नहीं कहूंगा कि आपके डिज़ाइन में कुछ भी गड़बड़ है। इस विचार को ध्यान में रखते हुए लक्षण सुझाए गए हैं, दूसरा बिंदु यहां देखें:

  • लक्षण व्यवहार को लागू करने वाले तरीकों का एक सेट प्रदान करता है।
  • एक विशेषता के लिए एक विधि की आवश्यकता होती है जो प्रदान किए गए व्यवहार के लिए मापदंडों के रूप में कार्य करती है।
  • [...]

स्टरली एट अल, ट्रैट्स: बिहेवियर की संगत इकाइयाँ, ECOOP'2003, LNCS 27, पीपी। 248–274, स्प्रिंगर वर्लग, 2003, पृष्ठ 2

इसलिए यह कहना शायद अधिक उचित होगा कि आप एक इंटरफ़ेस की आवश्यकता चाहते हैं , इसे "लागू" करने के लिए नहीं।

मुझे एक कारण नहीं दिखता है कि PHP में इस "विशेषता (इसके उपभोक्ता वर्गों को लागू करने के लिए) एक इंटरफ़ेस" सुविधा की आवश्यकता होना असंभव है, लेकिन वर्तमान में यह गायब हो रहा है।

उनके उत्तर में @Danack नोट के रूप में , आप गुण का उपयोग करने वाले वर्गों से उन्हें "आवश्यकता" करने के लिए विशेषता में सार कार्यों का उपयोग कर सकते हैं। दुर्भाग्य से आप निजी कार्यों के साथ ऐसा नहीं कर सकते ।


1

मैं @Danack की प्रतिक्रिया से सहमत हूं, हालांकि मैं इसे थोड़ा पूरक करूंगा।

वास्तव में छोटा संस्करण सरल है क्योंकि आप नहीं कर सकते। यही नहीं ट्रिट्स काम करते हैं।

मैं केवल कुछ मामलों के बारे में सोच सकता हूं जिसमें आप जो अनुरोध करते हैं वह आवश्यक है और भाषा की विफलता की तुलना में डिजाइन की समस्या के रूप में अधिक स्पष्ट है। ज़रा सोचिए कि इस तरह का एक इंटरफ़ेस है:

interface Weaponize
{
    public function hasAmmunition();
    public function pullTrigger();
    public function fire();
    public function recharge();
}

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

trait Triggerable
{
    public function pullTrigger()
    {
        if ($this->hasAmmunition()) {
            $this->fire();
        }
    }
}

class Warrior
{
    use Triggerable;
}

एक आसान समाधान यह है कि उन कार्यों को लागू करने के लिए गुण का उपयोग करने वाले वर्ग को मजबूर करने के लिए बस :

trait Triggerable
{
    public abstract function hasAmmunition();
    public abstract function fire();

    public function pullTrigger()
    {
        if ($this->hasAmmunition()) {
            $this->fire();
        }
    }
}

इसलिए विशेषता पूरी तरह से इंटरफ़ेस पर निर्भर नहीं है , लेकिन इसके कार्यों में से एक को लागू करने का प्रस्ताव है, क्योंकि विशेषता का उपयोग करते समय वर्ग अमूर्त विधियों के कार्यान्वयन की मांग करेगा।

अंतिम नक्शा

interface Weaponize
{
    public function hasAmmunition();
    public function pullTrigger();
    public function fire();
    public function recharge();
}

trait Triggerable
{
    public abstract function hasAmmunition();
    public abstract function fire();

    public function pullTrigger()
    {
        if ($this->hasAmmunition()) {
            $this->fire();
        }
    }
}


class Warrior implements Weaponize
{
    use Triggerable;

    public function hasAmmunition()
    {
        // TODO: Implement hasAmmunition() method.
    }

    public function fire()
    {
        // TODO: Implement fire() method.
    }

    public function recharge()
    {
        // TODO: Implement recharge() method.
    }
}

कृपया मेरी अंग्रेजी बहाना

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.