PHP 7 इंटरफेस, वापसी प्रकार संकेत और स्व


89

अद्यतन : PHP 7.4 अब सहसंयोजक और विरोधाभासी का समर्थन करता है जो इस प्रश्न में उठाए गए प्रमुख मुद्दे को संबोधित करता है।


मैं PHP 7 में रिटर्न टाइप हिंटिंग का उपयोग करके किसी समस्या में चला गया हूं। मेरी समझ यह है कि संकेत देने का : selfअर्थ है कि आप एक कार्यान्वयन वर्ग के लिए खुद को वापस करने का इरादा रखते हैं। इसलिए मैंने : selfयह बताने के लिए अपने इंटरफेस में इस्तेमाल किया , लेकिन जब मैंने वास्तव में इंटरफ़ेस को लागू करने की कोशिश की तो मुझे संगतता त्रुटियां मिलीं।

निम्नलिखित समस्या का एक सरल प्रदर्शन है जिसे मैंने चलाया है:

interface iFoo
{
    public function bar (string $baz) : self;
}

class Foo implements iFoo
{

    public function bar (string $baz) : self
    {
        echo $baz . PHP_EOL;
        return $this;
    }
}

(new Foo ()) -> bar ("Fred") 
    -> bar ("Wilma") 
    -> bar ("Barney") 
    -> bar ("Betty");

अपेक्षित आउटपुट था:

फ्रेड विल्मा बार्नी बेट्टी

वास्तव में मुझे क्या मिलता है:

PHP घातक त्रुटि: फू की घोषणा :: बार (int $ baz): फू को iFoo :: bar (int $ baz) के साथ संगत होना चाहिए: लाइन 7 में test.php में iFoo

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

क्या यह PHP में एक निरीक्षण है या यह एक जानबूझकर डिजाइन निर्णय है? अगर यह पूर्व है तो क्या इसे PHP 7.1 में तय करने का कोई मौका है? यदि नहीं, तो रिटर्न हिंटिंग का सही तरीका क्या है कि आपका इंटरफ़ेस आपको उस उदाहरण को वापस करने की उम्मीद करता है जिसे आपने अभी-अभी चाइनिंग के लिए विधि कहा है?


मुझे लगता है कि यह PHP रिटर्न टाइप-हिंटिंग में एक त्रुटि है, शायद आपको इसे बग के रूप में उठाना चाहिए ; लेकिन इस देर के चरण में PHP 7.1 में आने के लिए किसी भी फिक्स की संभावना नहीं है
मार्क बेकर

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

ब्याज से बाहर, आप अपनी व्याख्या कहां पढ़ रहे हैं कि selfरिटर्न प्रकार कैसे काम करना चाहिए?
एडम कैमरन

@ अदम: ऐसा लगता है जैसे self"इसका मतलब है कि आपने इस पर लौटाए गए उदाहरण को लौटाया है, न कि कुछ और उदाहरण जो समान इंटरफ़ेस को लागू करते हैं"। मुझे याद है कि जावा के पास एक समान रिटर्न प्रकार था (हालांकि मुझे जावा प्रोग्रामिंग किए हुए कुछ समय हो गया है)
गॉर्डन

1
हाय गॉर्डन। जब तक यह कहीं काम करने के लिए प्रलेखित नहीं किया जाता है, तब तक मैं इस बात पर भरोसा नहीं करूंगा कि यह तार्किक वास्तविकता हो सकती है। मैं जिस स्थिति का वर्णन करता हूं, उसके साथ टीबीएच, मैं यथासंभव घोषित करूंगा और वापसी के प्रकार के रूप में iFoo का उपयोग करूंगा। क्या ऐसी स्थिति है जिसमें वास्तव में काम नहीं होगा? (मुझे एहसास है कि यह "सलाह" है / राय "एक उत्तर" के बजाय, कहा कि
एडम कैमरन

जवाबों:


94

selfउदाहरण के लिए संदर्भित नहीं करता है, यह वर्तमान वर्ग को संदर्भित करता है। एक इंटरफ़ेस के लिए यह निर्दिष्ट करने का कोई तरीका नहीं है कि एक ही उदाहरण लौटाया जाना चाहिए - selfजिस तरीके से आप प्रयास कर रहे हैं उसका उपयोग केवल यह लागू करेगा कि लौटा हुआ उदाहरण एक ही वर्ग का हो।

कहा कि PHP में वापसी प्रकार की घोषणाएं अपरिवर्तनीय होनी चाहिए, जबकि आप जो प्रयास कर रहे हैं वह सहसंयोजक है।

आपका उपयोग selfइसके बराबर है:

interface iFoo
{
    public function bar (string $baz) : iFoo;
}

class Foo implements iFoo
{

    public function bar (string $baz) : Foo  {...}
}

जिसकी अनुमति नहीं है।


वापसी प्रकार घोषणाएं आरएफसी है यह कहना :

विरासत के दौरान घोषित रिटर्न प्रकार का प्रवर्तन अपरिवर्तनीय है; इसका मतलब यह है कि जब एक उप-प्रकार एक मूल विधि को ओवरराइड करता है, तो बच्चे का वापसी प्रकार माता-पिता से बिल्कुल मेल खाना चाहिए और छूट नहीं सकता है। यदि माता-पिता रिटर्न प्रकार की घोषणा नहीं करते हैं, तो बच्चे को एक घोषित करने की अनुमति है।

...

इस RFC ने मूल रूप से सहसंयोजक वापसी प्रकार प्रस्तावित किए थे, लेकिन कुछ मुद्दों के कारण इसे बदलकर अपरिवर्तनीय कर दिया गया था। भविष्य में कुछ बिंदु पर सहसंयोजक वापसी प्रकार जोड़ना संभव है।


समय के लिए कम से कम सबसे अच्छा आप कर सकते हैं:

interface iFoo
{
    public function bar (string $baz) : iFoo;
}

class Foo implements iFoo
{

    public function bar (string $baz) : iFoo  {...}
}

18
उस ने कहा, मुझे staticकाम के वापसी प्रकार-संकेत की उम्मीद होगी , लेकिन यह भी मान्यता प्राप्त नहीं है
मार्क बेकर

मुझे लगा कि यह मामला होगा, और इस तरह से मैं इस मुद्दे को हल करने जा रहा हूं। हालाँकि, मैंने केवल उपयोग करने को प्राथमिकता दी है: स्वयं यदि संभव हो तो क्योंकि यदि कोई वर्ग इंटरफ़ेस लागू कर रहा है तो स्वयं का एक वापसी मूल्य भी निहित है, इंटरफ़ेस का एक उदाहरण का एक वापसी मूल्य भी है।
गॉर्डन

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

आपके उद्धरण के एक हिस्से के लिए एक महत्वपूर्ण प्रस्तावना यहां देखी गई है: " सहसंयोजक वापसी प्रकार को ध्वनि माना जाता है और कई अन्य भाषाओं में उपयोग किया जाता है (सी ++ और जावा लेकिन नहीं सी # मेरा मानना ​​है)। यह आरएफसी मूल रूप से कोवरिएन्ट रिटर्न प्रकारों का प्रस्ताव करता है। कुछ मुद्दों की वजह से अपरिवर्तनीय में बदल दिया गया था। " मैं उत्सुक हूँ कि PHP में क्या मुद्दे थे। उनकी डिजाइन पसंद कई सीमाओं का कारण बनती है जो लक्षण के साथ अजीब मुद्दों का भी कारण बनती हैं, उन्हें कई मामलों में कुछ हद तक बेकार कर देती हैं जब तक कि आप वापसी प्रकार के प्रतिबंधों को ढीला नहीं करते (जैसा कि नीचे कुछ उत्तरों में देखा गया है)। अधिक निराश।
जॉन पंचो

1
@MarkBaker रिटर्न प्रकार staticPHP 8 में जोड़ा जा रहा है।
रिकार्डो बॉस

16

यह एक समाधान भी हो सकता है, कि आप इंटरफ़ेस में वापसी प्रकार को स्पष्ट रूप से परिभाषित नहीं करते हैं, केवल PHPDoc में और फिर आप कार्यान्वयन में निश्चित रिटर्न प्रकार को परिभाषित कर सकते हैं:

interface iFoo
{
    public function bar (string $baz);
}

class Foo implements iFoo
{
    public function bar (string $baz) : Foo  {...}
}

2
या Fooसिर्फ उपयोग के बजाय self
बजाय

2

मामले में, जब आप इंटरफ़ेस से बाध्य करना चाहते हैं, तो वह विधि ऑब्जेक्ट को लौटा देगी, लेकिन ऑब्जेक्ट का प्रकार इंटरफ़ेस का प्रकार नहीं होगा, लेकिन स्वयं वर्ग, तो आप इसे इस तरह से लिख सकते हैं:

interface iFoo {
    public function bar (string $baz) : object;
}

class Foo implements iFoo {
    public function bar (string $baz) : self  {...}
}

यह PHP 7.4 से काम कर रहा है।



0

यह मेरे लिए अपेक्षित व्यवहार की तरह दिखता है।

बस इसके बजाय Foo::barलौटने के लिए अपने तरीके को बदलें और इसके साथ रहें।iFooself

स्पष्टीकरण:

selfजैसा कि इंटरफ़ेस में उपयोग किया जाता है, जिसका अर्थ है "प्रकार की वस्तु iFoo।"
selfजैसा कि कार्यान्वयन में उपयोग किया जाता है, जिसका अर्थ है "प्रकार की वस्तु Foo।"

इसलिए, इंटरफ़ेस और कार्यान्वयन में वापसी प्रकार स्पष्ट रूप से समान नहीं हैं।

टिप्पणियों में से एक में जावा का उल्लेख है और क्या आपके पास यह मुद्दा होगा। जवाब है हां, आपके पास एक ही मुद्दा होगा यदि जावा ने आपको उस तरह का कोड लिखने की अनुमति दी है - जो यह नहीं करता है। चूंकि जावा आपको PHP के selfशॉर्टकट के बजाय प्रकार के नाम का उपयोग करने की आवश्यकता है , आप वास्तव में इसे कभी नहीं देख सकते हैं। ( जावा में इसी तरह के मुद्दे की चर्चा के लिए यहां देखें ।)


तो घोषित करना self, घोषित करने के समान है MyClass::class?
पेटेरचूला

1
@ लेजर हां, यह है।
मोशे कट्ज़

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