PHP में अवैध: वहाँ एक OOP डिजाइन कारण है?


16

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

<?php

/**
 * Marker interface
 */
interface IConfig {}

/**
 * An api sdk tool
 */
interface IApi
{
    public __construct(IConfig $cfg);
}

/**
 * Api configuration specific to http
 */
interface IHttpConfig extends IConfig
{
    public getSomeNiceHttpSpecificFeature();
}

/**
 * Illegal, but would be really nice to have.
 * Is this not allowed by design?
 */
interface IHttpApi extends IApi
{
    /**
     * This constructor must have -exactly- the same
     * signature as IApi, even though its first argument
     * is a subtype of the parent interface's required
     * constructor parameter.
     */
    public __construct(IHttpConfig $cfg);

}

जवाबों:


22

आइए एक दूसरे के लिए उपेक्षा करें कि प्रश्न में विधि क्या है __constructऔर इसे कॉल करें frobnicate। अब मान लीजिए कि आपके पास एक वस्तु apiक्रियान्वयन है IHttpApi, और एक वस्तु configक्रियान्वयन IHttpConfig। स्पष्ट रूप से, यह कोड इंटरफ़ेस को फिट करता है:

$api->frobnicate($config)

लेकिन Upcast हम लगता है जाने apiके लिए IApiकरने के लिए इसे पारित, उदाहरण के लिए function frobnicateTwice(IApi $api)। अब उस फ़ंक्शन में, frobnicateकॉल किया जाता है, और चूंकि यह केवल डील करता है IApi, इसलिए यह एक कॉल कर सकता है जैसे कि $api->frobnicate(new SpecificConfig(...))जहां SpecificConfigलागू होता है IConfigलेकिन नहीं IHttpConfig। किसी भी बिंदु पर किसी ने भी प्रकार के साथ कुछ भी नहीं किया है, फिर IHttpApi::frobnicateभी एक SpecificConfigऐसा स्थान मिला जहां यह अपेक्षित था IHttpConfig

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

औपचारिक रूप से, आप बहुरूपता, विचरण के आसपास के एक क्लासिक जाल में चले गए हैं । एक प्रकार की सभी घटनाओं को Tउपप्रकार द्वारा प्रतिस्थापित नहीं किया जा सकता है U। इसके विपरीत, एक प्रकार की सभी घटनाओं को सुपरपाइपT द्वारा प्रतिस्थापित नहीं किया जा सकता है । सावधानीपूर्वक विचार (या बेहतर अभी तक, प्रकार के सिद्धांत का सख्त अनुप्रयोग) आवश्यक है। S

वापस आ रहा है __construct: AFAIK के बाद से आप वास्तव में एक इंटरफ़ेस लागू नहीं कर सकते, केवल एक ठोस कार्यान्वयनकर्ता, यह एक व्यर्थ प्रतिबंध की तरह लग सकता है (यह कभी भी इंटरफ़ेस के माध्यम से कॉल नहीं किया जाएगा)। लेकिन उस मामले __constructमें, इंटरफ़ेस में शामिल क्यों करना शुरू करने के लिए? बावजूद, __constructयहां विशेष-मामले में इसका उपयोग बहुत कम होगा ।


19

हां, यह सीधे लिस्कोव सबस्टीट्यूशन सिद्धांत (एलएसपी) से है । जब आप किसी विधि को ओवरराइड करते हैं, तो रिटर्न प्रकार अधिक विशिष्ट हो सकता है, जबकि प्रकार के तर्क समान रहने चाहिए या अधिक सामान्य हो सकते हैं।

यह अन्य तरीकों से स्पष्ट है __construct। विचार करें:

class Vehicle {}
class Car extends Vehicle {}
class Motorcycle extends Vehicle {}

class Driver {
    public drive(Vehicle $v) { ... }
}
class CarDriver extends Driver {
    public drive(Car $c) { ... }
}

CarDriverहै Driver, इसलिए एक CarDriverउदाहरण कुछ भीDriver कर सकता है जो कर सकता है। ड्राइविंग शामिल है Motorcycles, क्योंकि यह सिर्फ एक है Vehicle। लेकिन तर्क प्रकार driveयह कहता है कि CarDriverकेवल एक ड्राइव कर सकता है Car- एक विरोधाभास: एक उचित उपवर्ग CarDriver नहीं हो सकता है Driver

रिवर्स अधिक समझ में आता है:

class CarDriver {
    public drive(Car $c) { ... }
}
class MultiTalentedDriver extends CarDriver {
    public drive(Vehicle $v) { ... }
}

A CarDriverकेवल Cars चला सकता है । A MultiTalentedDriverभी Cars चला सकता है , क्योंकि a Carकेवल a है Vehicle। इसलिए, MultiTalentedDriverका एक उचित उपवर्ग है CarDriver

आपके उदाहरण में, किसी भी IApiएक के साथ निर्माण किया जा सकता है IConfig। यदि IHttpApiइसका एक उपप्रकार है IApi, तो हमें IHttpApiकिसी भी IConfigउदाहरण का उपयोग करने में सक्षम होना चाहिए - लेकिन यह केवल स्वीकार करता है IHttpConfig। यह एक विरोधाभास है।


सभी ड्राइवर कार और मोटरसाइकिल दोनों नहीं चला सकते ...
sakisk

3
@ हाइफ़: इस विशेष रूप से अमूर्त में, वे न केवल कर सकते हैं, उन्हें करना चाहिए। क्योंकि, जैसा कि आप देख सकते हैं, कोई Driverभी ड्राइव कर सकता है Vehicle, और चूंकि दोनों Carऔर Motorcycleफैली हुई है Vehicle, सभी Driverको दोनों को संभालने में सक्षम होना चाहिए।
एलेक्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.