PHP 5.2+ अमूर्त स्टेटिक क्लास के तरीकों को क्यों नहीं रोकता है?


121

PHP 5.2 में सख्त चेतावनी को सक्षम करने के बाद, मैंने एक परियोजना से सख्त मानकों की चेतावनी का लोड देखा जो मूल रूप से सख्त चेतावनी के बिना लिखा गया था:

सख्त मानक : स्टेटिक फंक्शन प्रोग्राम :: getSelectSQL () Program.class.inc में सार नहीं होना चाहिए

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

मुझे इस परिवर्तन के संदर्भ यहां मिले :

अमूर्त स्थिर वर्ग कार्यों को गिरा दिया। एक ओवरसाइट के कारण, PHP 5.0.x और 5.1.x कक्षाओं में सार स्थिर कार्यों की अनुमति दी। PHP 5.2.x के रूप में, केवल इंटरफेस उनके पास हो सकते हैं।

मेरा सवाल है: क्या कोई स्पष्ट तरीके से समझा सकता है कि पीएचपी में अमूर्त स्थिर कार्य क्यों नहीं होना चाहिए?


12
नए पाठकों को ध्यान देना चाहिए कि PHP 7 में इस तर्कहीन प्रतिबंध को हटा दिया गया है
मार्क एमी

जवाबों:


76

स्थिर विधियाँ उस वर्ग से संबंधित हैं जिसने उन्हें घोषित किया था। वर्ग का विस्तार करते समय, आप एक ही नाम की एक स्थिर विधि बना सकते हैं, लेकिन आप वास्तव में एक स्थिर सार पद्धति को लागू नहीं कर रहे हैं।

स्थिर तरीकों के साथ किसी भी वर्ग का विस्तार करने के लिए समान है। यदि आप उस वर्ग का विस्तार करते हैं और एक ही हस्ताक्षर की एक स्थिर विधि बनाते हैं, तो आप वास्तव में सुपरक्लास की स्थैतिक विधि को ओवरराइड नहीं कर रहे हैं

EDIT (सितम्बर 16, 2009)
इस पर अपडेट करें। PHP 5.3 चलाना, मुझे लगता है कि अमूर्त स्थिर वापस आ गया है, अच्छे या बीमार के लिए। ( अधिक जानकारी के लिए http://php.net/lsb देखें )

सुधार (philfreo द्वारा)
abstract staticअभी भी पीएचपी 5.3 में अनुमति नहीं है, LSB संबंधित लेकिन अलग है।


3
ठीक है, तो क्या होगा यदि मैं सभी बच्चों में फ़ंक्शन getSelectSQL () की आवश्यकता को लागू करना चाहता हूं जो मेरे अमूर्त वर्ग का विस्तार करते हैं? मूल श्रेणी में getSelectSQL () मौजूद होने का कोई वैध कारण नहीं है। कार्रवाई की सबसे अच्छी योजना क्या है? कारण मैंने अमूर्त स्थैतिक चुना है कि सभी बच्चों में getSelectSQL () लागू होने तक कोड संकलित नहीं होगा।
आर्टेम रसाकोवस्की

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

7
सार स्थिर अभी भी PHP 5.3 में बंद है। देर से स्थिर बाइंडिंग का इससे कोई लेना देना नहीं है। यह भी देखें stackoverflow.com/questions/2859633
Artefacto

40
मेरी राय में यह सख्त चेतावनी सिर्फ बेवकूफ है क्योंकि PHP में "देर से स्थैतिक बंधन" है, जो स्वाभाविक रूप से स्थैतिक तरीकों का उपयोग करने का विचार प्रदान करता है जैसे कि कक्षा स्वयं एक वस्तु थी (जैसे, रूबी में कहें)। जिसके कारण स्थैतिक विधि अतिभारित abstract staticहो जाती है और इस मामले में उपयोगी हो सकती है।
मृत्यु

4
यह उत्तर अस्पष्ट है। "अभी भी अनुमति नहीं है" बस इसका मतलब है कि आपको E_STRICT स्तर की चेतावनी मिलेगी, कम से कम 5.3+ में आप अमूर्त स्थिर कार्यों को बनाने के लिए पूरी तरह से स्वागत करते हैं, उन्हें विस्तारित कक्षाओं में लागू करते हैं, और फिर उन्हें स्थैतिक :: कीवर्ड के माध्यम से संदर्भित करते हैं। जाहिर है कि अभिभावक वर्ग का स्थैतिक संस्करण अभी भी है और इसे सीधे (स्व: या स्थैतिक :: उस वर्ग के अंदर) के रूप में नहीं कहा जा सकता है क्योंकि यह अमूर्त है और यह वस्तुतः त्रुटि होगा जैसे कि आप एक नियमित गैर-स्थैतिक सार फ़ंक्शन कहते हैं। कार्यात्मक रूप से यह उपयोगी है, मैं उस प्रभाव के लिए @dmitry भावनाओं से सहमत हूं।
20

79

यह एक लंबी, दुखद कहानी है।

जब PHP 5.2 ने पहली बार इस चेतावनी को पेश किया, तो देर से स्थिर बाइंडिंग भाषा में नहीं थे। यदि आप देर से स्थैतिक बाइंडिंग से परिचित नहीं हैं, तो ध्यान दें कि कोड इस तरह से काम नहीं करता है जिस तरह से आप उम्मीद कर सकते हैं:

<?php

abstract class ParentClass {
    static function foo() {
        echo "I'm gonna do bar()";
        self::bar();
    }

    abstract static function bar();
}

class ChildClass extends ParentClass {
    static function bar() {
        echo "Hello, World!";
    }
}

ChildClass::foo();

सख्त मोड की चेतावनी को छोड़कर, ऊपर दिया गया कोड काम नहीं करता है। self::bar()में कॉल foo()स्पष्ट रूप को दर्शाता है bar()की विधि ParentClass, तब भी जब foo()की विधि के रूप में कहा जाता है ChildClass। यदि आप इस कोड को सख्त मोड से चलाने का प्रयास करते हैं, तो आपको " PHP घातक त्रुटि: सार पद्धति को कॉल नहीं किया जा सकता है

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

लेकिन तब PHP 5.3 उस वर्ग को संदर्भित करने की क्षमता में जोड़ा गया जिस पर एक विधि को staticकीवर्ड के माध्यम से बुलाया गया था (कीवर्ड के विपरीत self, जो हमेशा उस वर्ग को संदर्भित करता है जिसमें विधि को परिभाषित किया गया था )। आप को बदलते हैं self::bar()करने के लिए static::bar()ऊपर मेरी उदाहरण में, यह पीएचपी 5.3 में और ऊपर ठीक काम करता है। आप के बारे में अधिक पढ़ सकते हैं selfबनाम staticपर नए आत्म बनाम नई स्थिर

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

आप अभी भी, मुझे लगता है, चेतावनी रखने के लिए एक मामला बना सकते हैं। उदाहरण के लिए, आप तर्क दे सकता है (बदल कर यह तय करने के बाद भी कि जब पीएचपी की मदद से आप अमूर्त वर्ग के स्थिर तरीकों कहते हैं, ऊपर मेरे उदाहरण में selfसाथ staticआप एक सार्वजनिक विधि उजागर कर रहे हैं) ParentClass::foo()जो है टूट और आप नहीं है वास्तव में चाहते हैं कि बेनकाब। एक गैर-स्थैतिक वर्ग का उपयोग करना - अर्थात, सभी तरीकों को उदाहरण के तरीके बनाना और ParentClassसभी के बच्चों को एकल या कुछ और बनाना - इस समस्या को हल करेगा, क्योंकि ParentClass, सार होने के नाते, तुरंत नहीं किया जा सकता है और इसलिए इसकी आवृत्ति के तरीके नहीं हो सकते हैं बुलाया जाए। मुझे लगता है कि यह तर्क कमजोर है (क्योंकि मुझे लगता है कि उजागर करनाParentClass::foo() एक बड़ी बात नहीं है और स्थिर वर्गों के बजाय एकल का उपयोग करना अक्सर अनावश्यक रूप से क्रिया और बदसूरत होता है), लेकिन आप यथोचित असहमत हो सकते हैं - यह कुछ व्यक्तिपरक कॉल है।

तो इस तर्क के आधार पर, PHP देवों ने भाषा में चेतावनी को सही रखा है?

उह, बिल्कुल नहीं

PHP बग रिपोर्ट 53081, ऊपर लिंक, static::foo()निर्माण के अलावा के बाद से गिराए जाने की चेतावनी के लिए बुलाया गया था, जो अमूर्त स्थिर तरीकों को उचित और उपयोगी बना दिया था। रासमस लेरडोर्फ (PHP का निर्माता) अनुरोध को फर्जी करार देकर शुरू होता है और चेतावनी को सही ठहराने की कोशिश के लिए खराब तर्क की लंबी श्रृंखला से गुजरता है। फिर, आखिरकार, यह विनिमय होता है:

जियोर्जियो

मुझे पता है पर:

abstract class cA
{
      //static function A(){self::B();} error, undefined method
      static function A(){static::B();} // good
      abstract static function B();
}

class cB extends cA
{
    static function B(){echo "ok";}
}

cB::A();

Rasmus

ठीक है, यह ठीक है कि यह कैसे काम करना चाहिए।

जियोर्जियो

लेकिन इसकी अनुमति नहीं है :(

Rasmus

क्या अनुमति नहीं है?

abstract class cA {
      static function A(){static::B();}
      abstract static function B();
}

class cB extends cA {
    static function B(){echo "ok";}
}

cB::A();

यह ठीक काम करता है। आप स्पष्ट रूप से स्वयं :: बी () नहीं कह सकते, लेकिन स्थिर :: बी () ठीक है।

रासमस द्वारा दावा किया गया कि उसके उदाहरण में कोड "ठीक काम करता है" झूठा है; जैसा कि आप जानते हैं, यह एक सख्त मोड चेतावनी फेंकता है। मुझे लगता है कि वह सख्त मोड के बिना परीक्षण कर रहा था। बावजूद, एक भ्रमित रासमस ने अनुरोध को गलत तरीके से "फर्जी" के रूप में बंद कर दिया।

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

सौभाग्य से, आकलन योग्य निकिता पोपोव ने PHP 7 में PHP RFC के भाग के रूप में भाषा से चेतावनी को हटा दिया है : E_STRICT नोटिस को फिर से देखें । अंततः, पवित्रता प्रबल हो गई है, और PHP 7 जारी होने के बाद हम सभी abstract staticइस मूर्खतापूर्ण चेतावनी को प्राप्त किए बिना खुशी से उपयोग कर सकते हैं ।


70

इस मुद्दे के लिए एक बहुत ही सरल काम है, जो वास्तव में डिजाइन के दृष्टिकोण से समझ में आता है। जैसा कि जोनाथन ने लिखा है:

स्थिर तरीकों के साथ किसी भी वर्ग का विस्तार करने के लिए समान है। यदि आप उस वर्ग का विस्तार करते हैं और एक ही हस्ताक्षर की एक स्थिर विधि बनाते हैं, तो आप वास्तव में सुपरक्लास की स्थैतिक विधि को ओवरराइड नहीं कर रहे हैं

तो, आप के आसपास एक काम के रूप में यह कर सकता है:

<?php
abstract class MyFoo implements iMyFoo {

    public static final function factory($type, $someData) {
        // don't forget checking and do whatever else you would
        // like to do inside a factory method
        $class = get_called_class()."_".$type;
        $inst = $class::getInstance($someData);
        return $inst;
    }
}


interface iMyFoo {
    static function factory($type, $someData);
    static function getInstance();
    function getSomeData();
}
?>

और अब आप लागू करते हैं कि MyFoo को उपवर्गित करने वाला कोई वर्ग getInstance static पद्धति और सार्वजनिक getSomeData विधि लागू करता है। और यदि आप MyFoo को उपवर्गित नहीं करते हैं, तो आप समान कार्यक्षमता के साथ एक वर्ग बनाने के लिए iMyFoo को लागू कर सकते हैं।


2
क्या फ़ंक्शन को संरक्षित करने के लिए इस पैटर्न के साथ संभव है । जब मैं ऐसा करता हूं, तो इसका मतलब है कि MyFoo फेंक चेतावनी देने वाली कक्षाएं जो getInstance सार्वजनिक होनी चाहिए। और आप एक इंटरफ़ेस परिभाषा में संरक्षित नहीं रख सकते।
आर्टफ्लोरोबोट

3
कुछ समय static::उपयोगी हो सकता है।
seyed

3
लक्षण के साथ काम नहीं करता है। अगर केवल abstract static
ट्रैक्ट्स

1
एक अंतरफलक का उपयोग शायद यहाँ सबसे अच्छा समाधान है। +1।
जुआन कार्लोस कोटो

यह वास्तव में बहुत सरल है क्योंकि इसकी सरलता है। +1
जी। स्टीवर्ट

12

मुझे पता है यह पुराना है लेकिन ...।

क्यों न केवल उस अपवाद को उस मूल वर्ग की स्थैतिक विधि के रूप में फेंक दें, इस तरह से यदि आप इसे ओवरराइड नहीं करते हैं तो इसका कारण बनता है।


1
यह मदद नहीं करता है, अपवाद स्थैतिक विधि के कॉल पर होता है - यदि आप इसे ओवरराइड नहीं करते हैं तो उसी समय एक 'विधि मौजूद नहीं है' त्रुटि सामने आएगी।
BT

3
@ मेरा मतलब है, विधि को अमूर्त घोषित न करें, इसे लागू करें, लेकिन जब इसे बुलाया जाता है तो सिर्फ एक अपवाद फेंक दें, जिसका अर्थ है कि यदि यह ओवरराइड हो गया है तो इसे न फेंकें।
पेटा

यह सबसे सुरुचिपूर्ण समाधान लगता है।
एलेक्स एस

संकलित समय पर इस तरह के कुछ देखने के लिए बेहतर है, रन समय की तुलना में। उत्पादन में होने से पहले समस्या का पता लगाना आसान है क्योंकि आपको केवल फ़ाइल को लोड करना है, न कि यह पता लगाने के लिए कोड निष्पादित करना है कि क्या इसकी खराब या गैर-अनुरूपता है
Rahly

4

मेरा तर्क है कि एक सार वर्ग / इंटरफ़ेस को प्रोग्रामर के बीच अनुबंध के रूप में देखा जा सकता है। यह इस बात से अधिक संबंधित है कि चीजों को कैसे देखना चाहिए / व्यवहार करना चाहिए और वास्तविक कार्यक्षमता को लागू नहीं करना चाहिए। जैसा कि php5.0 और 5.1.x में देखा गया है यह एक प्राकृतिक नियम नहीं है जो php डेवलपर्स को ऐसा करने से रोकता है, लेकिन अन्य भाषाओं में अन्य OO डिजाइन पैटर्न के साथ जाने का आग्रह करता है। मूल रूप से ये विचार अप्रत्याशित व्यवहार को रोकने की कोशिश करते हैं, अगर कोई पहले से ही अन्य भाषाओं से परिचित है।


यद्यपि यहाँ php संबंधित नहीं है, एक और अच्छी व्याख्या है: stackoverflow.com/questions/3284/…
merkuro

3
हे भगवान! जिन दो लोगों ने आपको अपमानित किया, वे उनके दिमाग से पूरी तरह से बाहर हैं! यह इस धागे पर सबसे व्यावहारिक जवाब है।
थियोडोर आर। स्मिथ

5
@ TheodoreR.Smith प्रवीण? इसमें त्रुटियां हैं और यह बमुश्किल सुसंगत है। यह दावा कि अमूर्त वर्ग "वास्तविक कार्यक्षमता को लागू नहीं करते हैं " आवश्यक रूप से सही नहीं है, और यह इंटरफेस के अलावा उनमें से संपूर्ण बिंदु है। इस दावे में कि "यह एक प्राकृतिक कानून नहीं है जो php डेवलपर्स को ऐसा करने से रोकता है" , मुझे नहीं पता कि "यह" क्या है। और इस दावे में कि "मूल रूप से ये विचार अप्रत्याशित व्यवहार को रोकने की कोशिश करते हैं" , मुझे नहीं पता कि "ये विचार" या संभावित "अप्रत्याशित व्यवहार" क्या हैं। इससे जो भी अंतर्दृष्टि निकाली, वह मुझ पर खो गई।
मार्क अमेरी

2

मुझे स्थैतिक अमूर्त कार्यों को रोकने के लिए कोई कारण नहीं दिखता है। सबसे अच्छा तर्क है कि उन्हें मना करने का कोई कारण नहीं है, कि उन्हें जावा में अनुमति दी गई है। प्रश्न हैं: - क्या तकनीकी रूप से संभव हैं? - हाँ, चूंकि PHP 5.2 में अस्तित्व में है और वे जावा में मौजूद हैं। तो whe कर सकता है। हम इसे कर सकते हैं? - क्या वे समझ में आते हैं? हाँ। यह एक वर्ग के एक हिस्से को लागू करने और उपयोगकर्ता के लिए एक वर्ग के दूसरे हिस्से को छोड़ने के लिए समझ में आता है। यह गैर-स्थिर कार्यों में समझ में आता है, इसे स्थिर कार्यों के लिए क्यों नहीं बनाया जाना चाहिए? स्थैतिक कार्यों का एक उपयोग वे वर्ग हैं जहाँ एक से अधिक उदाहरण (एकल) नहीं होने चाहिए। उदाहरण के लिए एक एन्क्रिप्शन इंजन। इसे कई उदाहरणों में मौजूद होने की आवश्यकता नहीं है और इसे रोकने के लिए कारण हैं - उदाहरण के लिए, आपको घुसपैठियों के खिलाफ स्मृति के केवल एक हिस्से की रक्षा करनी होगी। तो यह इंजन के एक हिस्से को लागू करने और उपयोगकर्ता के लिए एन्क्रिप्शन एल्गोरिथ्म को छोड़ने के लिए सही समझ में आता है। यह केवल एक उदाहरण है। यदि आप स्थिर कार्यों का उपयोग करने के आदी हैं तो आप बहुत अधिक पाएंगे।


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

0

Php 5.4+ उपयोग विशेषता में:

trait StaticExample {
    public static function instance () {
    return new self;
    }
}

और अपनी कक्षा में भीख माँगने पर रखो:

use StaticExample;

1
मैं abstract public static function get_table_name();एक विशेषता में डालने में सक्षम था और उस सार वर्ग के भीतर और अधिक E_STRICT चेतावनियों के साथ उस विशेषता का उपयोग करता था! यह अभी भी बच्चों में स्थिर विधि को परिभाषित करने के रूप में लागू किया गया था जैसा कि मुझे उम्मीद थी। बहुत खुबस!
प्रोग्रामर

-1

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


4
मुझे लगता है कि उसका मतलब है "सख्त मानक" चेतावनी।
जैकब ह्यूम

2
क्या "मुद्दों" का दावा है कि देर से स्थैतिक बाइंडिंग है? आप दावा करते हैं कि वे "टूटे हुए" हैं, जो एक साहसिक दावा है, जो बिना सबूत या स्पष्टीकरण के यहां बनाया गया है। फीचर ने मेरे लिए हमेशा ठीक काम किया है, और मुझे लगता है कि यह पोस्ट बकवास है।
मार्क अमेरी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.