2009-04-14 13 views
20

कि क्या पीएचपी विधि ओवरलोडिंग, विरासत, और बहुरूपता जैसी सुविधाओं का समर्थन करता है यह पता लगाने की कोशिश कर रहा है, मुझे पता चला:क्या PHP में वास्तव में बहुरूपता में बहुरूपता की तरह दिखता है?

  • यह विधि ओवरलोडिंग का समर्थन नहीं करता
  • यह समर्थन विरासत

लेकिन मैं करता polymorphism के बारे में अनिश्चित हूँ। मैंने इंटरनेट पर यह गुगलिंग पाया:

I should note that in PHP the polymorphism isn't quite the way it should be. I mean that it does work, but since we have a weak datatype, its not correct.

तो क्या यह वास्तव में बहुरूपता है?

संपादित बस काफी एक निश्चित हाँ या नहीं PHP supports polymorphism के बगल में जगह नहीं कर सकते। मैं यह कहने के लिए घृणा करता हूं: "PHP बहुरूपता का समर्थन नहीं करता है", जब वास्तव में यह करता है। या ठीक इसके विपरीत।

+5

"PHP बहुरूपता का समर्थन करता है, लेकिन इसमें कुछ सीमाएं हैं।" टाडा। :) –

+0

धन्यवाद :) आपके उत्तर को ऊपर उठाया। –

+0

यह प्रश्न भाषा अज्ञेयवादी क्यों है? मुझे पूरी तरह से PHP के बारे में लगता है। – beldaz

उत्तर

31
class Animal { 
    var $name; 
    function __construct($name) { 
     $this->name = $name; 
    } 
} 

class Dog extends Animal { 
    function speak() { 
     return "Woof, woof!"; 
    } 
} 

class Cat extends Animal { 
    function speak() { 
     return "Meow..."; 
    } 
} 

$animals = array(new Dog('Skip'), new Cat('Snowball')); 

foreach($animals as $animal) { 
    print $animal->name . " says: " . $animal->speak() . '<br>'; 
} 

आप इसे जो भी चाहते हैं उसे लेबल कर सकते हैं, लेकिन यह मुझे polymorphism की तरह दिखता है।

+4

यकीन है, लेकिन पशु इंटरफेस निर्दिष्ट नहीं करता है कि एक स्पीच() विधि होगी। तो मैं एक नई वस्तु जैसे नई एफपीडीएफ() बना सकता था; और फिर इसे जानवरों की सरणी में जोड़ें। फिर क्या? यह कैसे बोलेंगे()? –

+0

आप पशु वर्ग में एक स्पीच विधि निर्दिष्ट कर सकते हैं, और यह कहा जाएगा कि क्या बच्चा वर्ग अपनी बोल निर्दिष्ट नहीं करता है। और यदि ऐसा होता है, तो आप इसे किसी भी तरह से माता-पिता :: बोल() के साथ कॉल कर सकते हैं; –

+1

तो आप कहेंगे कि यह polymorphism का समर्थन करता है। मैं इसे 'असुरक्षित' या 'कमजोर बहुलक व्यवहार' कहने की सोच रहा हूं। आपकी क्या राय है? –

4

तुम अब भी तरीकों ओवरराइड कर सकते हैं, बस उन्हें ओवरलोड नहीं। ओवरलोडिंग (सी ++ में) वह जगह है जहां आप एकाधिक विधियों के लिए एक ही विधि नाम का उपयोग करते हैं, केवल संख्याओं और पैरामीटर के प्रकार में भिन्न होते हैं। PHP में यह मुश्किल होगा क्योंकि यह कमजोर टाइप है।

ओवरराइडिंग वह जगह है जहां उप-वर्ग बेस क्लास में एक विधि को प्रतिस्थापित करता है। जो वास्तव में बहुरूपता का आधार है, और आप इसे PHP में कर सकते हैं।

+0

क्षमा करें, यह बिल्कुल मेरा मतलब नहीं है। मैं समझता हूं कि PHP में विधि अधिभार क्यों समर्थित नहीं है, और ओवरलोडिंग और ओवरराइडिंग के बीच का अंतर क्यों है। लेकिन क्या मैं यह घोषणा कर सकता हूं कि यह बहुरूपता का समर्थन करता है? –

+0

हम भ्रम देकर PHP में विधि अधिभार को कार्यान्वित कर सकते हैं जैसा कि मैंने अपने उत्तर में दिखाया है। –

6

__call() और __callStatic() विधि ओवरलोडिंग का समर्थन करना चाहिए। इस पर अधिक manual में उपलब्ध है। या आप वास्तव में क्या कर रहे हैं?

अद्यतन: मैं सिर्फ अन्य उत्तर देखा।

एक और तरीका है एक विधि ओवरलोड के लिए, निम्न पर विचार करें:

<?php 
public function foo() 
{ 
    $args = func_get_arg(); 
} 

निश्चित रूप से सुंदर नहीं है, लेकिन यह आप वस्तुतः आप जो कुछ भी करना चाहते हैं अनुमति देता है।

+1

यह एक अच्छा हैक है :) "ट्यूबल बॉक्स" में रखने के लिए अच्छा :) –

+0

टूल बॉक्स? :) हे ... हाँ, बस याद रखें, इसका उपयोग न करें। इसके अलावा, अगर आप बंदर पैचिंग के बाद हैं, तो रनकिट में देखें। – Till

+2

"होमर ट्यूबल बॉक्स" होमर सिम्पसन ने अपने टूलबॉक्स पर लिखा है। :) –

16

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

class myClass { 
    public function overloadedMethod() { 
     // func_num_args() is a build-in function that returns an Integer. 
     // the number of parameters passed to the method. 
     if (func_num_args() > 1) { 
      $param1 = func_get_arg(0); 
      $param2 = func_get_arg(1); 
      $this->_overloadedMethodImplementation2($param1,$param2) 
     } else { 
      $param1 = func_get_arg(0); 
      $this->_overloadedMethodImplementation1($param1) 
     } 
    } 

    protected function _overloadedMethodImplementation1($param1) { 
     // code 1 
    } 

    protected function _overloadedMethodImplementation2($param1,$param2) { 
     // code 2 
    } 
} 

वहाँ क्लीनर कार्यान्वयन हो सकता है, लेकिन यह सिर्फ एक नमूना है।

पीएचपी विरासत और इंटरफेस का समर्थन करता है। तो आप उनका उपयोग कर बहुरूपता प्राप्त कर सकते हैं।आप इस तरह से एक इंटरफेस हो सकता है:

// file: MyBackupInterface.php 
interface MyBackupInterface { 
    // saves the data on a reliable storage 
    public function saveData(); 
    public function setData(); 
} 

// file: myBackupAbstract.php 
require_once 'MyBackupInterface.php'; 
class MyBackupAbstract implements MyBackupInterface { 
    protected $_data; 
    public function setData($data) { 
     $this->_data= $data; 
    } 
    // there is no abstract modifier in PHP. so le'ts avoid this class to be used in other ways 
    public function __construct() { 
      throw new Exception('this class is abstract. you can not instantiate it'); 
    } 
} 

// file: BackupToDisk.php 
require_once 'MyBackupAbstract.php'; 
class BackupToDisk extends MyBackupAbstract { 
    protected $_savePath; 

    // implement other methods ... 

    public function saveData() { 
      // file_put_contents() is a built-in function to save a string into a file. 
      file_put_contents($this->_savePath, $this->_data); 
    } 
} 

// file: BackupToWebService.php 
require_once 'MyBackupAbstract.php'; 
class BackupToWebService extends MyBackupAbstract { 
    protected $_webService; 
    // implement other methods ... 

    public function saveData() { 
      // suppose sendData() is implemented in the class 
      $this->sendData($this->_data); 
    } 
} 
अब अपने आवेदन में

, तो आप इस तरह उपयोग हो सकता है:

// file: saveMyData.php 
// some code to populate $myData 
$backupSolutions = array(new BackupToDisk('/tmp/backup') , new BackupToWebService('webserviceURL')); 
foreach ($backupSolutions as $bs) { 
    $bs->setData($myData); 
    $bs->saveData(); 
} 

तुम ठीक कह रहे, पीएचपी मजबूत टाइप भाषा नहीं है, हम कभी नहीं उल्लेख किसी भी है कि आपके $ बैकअप समाधानों का 'MyBackupAbstract' या 'MyBackupInterface' होगा, लेकिन यह हमें polymorphism की प्रकृति होने से नहीं रोकता है जो एक ही तरीके का उपयोग करने पर अलग कार्यक्षमता है।

+2

+1 एक अच्छे उत्तर के लिए –

1
मैं यहाँ php क्या देखा है बहुरूपता का समर्थन नहीं करते, और न ही तरीकों अधिक भार के लिए

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

2

बहुरूपता निम्न विधियों में लागू किया जा सकता:

  1. method overriding - जैसा कि ऊपर सामान्य सुंदर था

  2. method overloading

आप द्वारा विधि से अधिक भार का भ्रम पैदा कर सकते हैं जादू विधि __call():

class Poly { 
    function __call($method, $arguments) { 
     if ($method == 'edit') { 
      if (count($arguments) == 1) { 

       return call_user_func_array(array($this,'edit1'), $arguments); 
      } else if (count($arguments) == 2) { 
       return call_user_func_array(array($this,'edit2'), $arguments); 
      } 
     } 
    } 
    function edit1($x) { 
     echo "edit with (1) parameter"; 
    } 

    function edit2($x, $y) { 
     echo "edit with (2) parameter"; 
    } 

} 

$profile = new Poly(); 
$profile->edit(1); 
$profile->edit(1,2); 

Expln:

1) Here we are utilizing the power of __call() of listening calls of 
    non-available  methods and 
2) after knowing it who had called with their inputs diverting them to desired 
    method 

In php, हम वास्तव में कर रहे working under the hood वांछित व्यवहार देने के लिए और भावना of method overloading

6

पीएचपी वर्ग आधारित बहुरूपता है, लेकिन लागू करने के लिए एक औपचारिक तंत्र का अभाव है तर्क के आधार पर देने के लिए बहुरूपता।

कक्षा आधारित बहुरूपता मतलब है कि आप एक आधार वर्ग के संदर्भ में सोच सकते हैं, और तरीकों बुलाया जा रहा है अंतिम वर्ग पर निर्भर है। उदाहरण के लिए, यदि आपके पास त्रिभुज और मंडल जैसे विभिन्न वर्गों की वस्तुओं की एक श्रृंखला है, और इनमें से प्रत्येक वर्ग एक ही कक्षा के आकार को बढ़ाता है, तो आप अपने सरणी को केवल आकारों के संग्रह के रूप में देख सकते हैं। आप आकार के माध्यम से लूप कर सकते हैं और प्रत्येक आकार की getArea() विधि को कॉल कर सकते हैं। पॉलीमोर्फिज्म ऐसी घटना है जिसके द्वारा getArea() विधि कहा जा रहा है वस्तु के वर्ग पर निर्भर करता है। यदि आपका आकार त्रिकोण है, त्रिकोण :: getArea() को सर्किल कहा जाता है, तो सर्किल :: getArea() को कॉल किया जाता है - भले ही आपका कोड सर्किल और त्रिकोण के बीच अंतर न करे, लेकिन प्रत्येक ऑब्जेक्ट को इस संबंध में मानता है केवल एक आकार ऑब्जेक्ट की कक्षा के आधार पर, कोड की एक ही पंक्ति को कोड के एक अलग ब्लॉक में निष्पादित किया जा रहा है।

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

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

3

PHP पॉलिमॉर्फिक कोड की अनुमति देता है जो अन्य भाषाओं में संकलन त्रुटि उत्पन्न करेगा। एक सरल यह दिखाता है। सबसे पहले सी ++ कोड है कि एक उम्मीद संकलन त्रुटि उत्पन्न:

class Base {}; 

class CommonDerivedBase { 
    public: 
    // The "= 0" makes the method and class abstract 
    // virtual means polymorphic method 
    virtual whoami() = 0; 
}; 

class DerivedBase : public CommonDerivedBase { 
    public:  
    void whoami() { cout << "I am DerivedBase \n"; } 
}; 

class Derived1 : public CommonDerivedBase { 
    public: 
    void whoami() { cout << "I am Derived1\n"; } 
}; 

class Derived2 : public CommonDerivedBase { 
public: 
void whoami() { cout << "I am Derived2\n"; } 
}; 

/* This will not compile */ 
void test_error(Base& db) 
{ 
    db.whoami(); 
} 

C++ कम्पाइलर क्योंकि बेस एक विधि Whoami बुलाया नहीं है लाइन db.whoami()

error: no member named 'whoami' in 'Base' 

के लिए यह त्रुटि संदेश जारी करेगा()। हालांकि, समान PHP कोड को रन टाइम तक ऐसी त्रुटियां नहीं मिलती हैं।

class Base {} 

abstract class DerivedCommonBase { 
    abstract function whoami(); 
} 

class Derived1 extends DerivedCommonBase { 

public function whoami() { echo "I am Derived1\n"; } 
} 

class Derived2 extends DerivedCommonBase { 

public function whoami() { echo "I am Derived2\n"; } 
} 

/* In PHP, test(Base $b) does not give a runtime error, as long as the object 
* passed at run time derives from Base and implements whoami(). 
*/ 
function test(Base $b) 
{ 
    $b->whoami(); 
} 

$b = new Base(); 
$d1 = new Derived1(); 
$d2 = new Derived2(); 

$a = array(); 

$a[] = $d1; 
$a[] = $d2; 

foreach($a as $x) { 

    echo test($x); 
} 

test($d1); 
test($d2); 
test($b); //<-- A run time error will result. 

foreach पाश उत्पादन

I am Derived1 
I am Derived2 

साथ काम करता है नहीं जब तक आप परीक्षण ($ ख) कॉल करें और अपना एक रन समय त्रुटि प्राप्त होगी बेस का एक उदाहरण गुजरती हैं। तो foreach के बाद, उत्पादन

I am Derived1 
I am Derived2 
PHP Fatal error: Call to undefined method Base::whoami() in 
home/kurt/public_html/spl/observer/test.php on line 22 

केवल एक चीज आप PHP सुरक्षित परीक्षण करने के लिए एक रन समय जांच जोड़ने के लिए है, तो $ ख वर्ग का एक उदाहरण है किया जाएगा बनाने के लिए क्या कर सकते हैं के बारे में हो जाएगा आप इरादा

function test(Base $b) 
{ 
    if ($b instanceof DerivedCommonBase) { 
    $b->whoami(); 
    } 
} 

लेकिन बहुरूपता के पूरे मुद्दे ऐसे रन टाइम चेकों को खत्म करने की है।

+0

मैं वास्तव में आपका बिंदु नहीं देखता हूं। आप कह रहे हैं, "अगर मैं एक वर्ग जो न तो विधि है और न ही औजार लागू करता है या किसी इंटरफ़ेस या वर्ग जो विधि है, मैं एक त्रुटि जो संकलन समय पर नहीं कर दिया गया प्राप्त करता फैली पर एक विधि कहते हैं।" कोड '$ myVariable = "abc" कोड के ठीक वही कहा जा सकता है; $ MyVariable-> MyTestMethod(); '। बेशक यह तार्किक है कि यदि आप पूरी तरह से असंबद्ध वस्तु पर एक यादृच्छिक फ़ंक्शन को कॉल यह नहीं चलता है। तथ्य यह है कि रनटाइम तक यह देखा नहीं जाता है क्योंकि PHP की गतिशील और कमजोर टाइपिंग की वजह से है। एर्गो, आपने एक पूरी तरह से गलत समझाया बहुरूपता प्रयास का प्रदर्शन किया। – Byson

+0

मेरी बात को प्रदर्शित करने के लिए, यहाँ कोड का परिणाम है: ' $ myVariable =" abc "; $ myVariable-> MyTestMethod(); ' --- 'घातक त्रुटि: किसी सदस्य को MyTestMethod() को गैर-ऑब्जेक्ट पर फ़ंक्शन करें ... \ test \ test2.php लाइन 5' पर हाँ तो हाँ, मैं देख रहा हूँ कि क्या अप्रत्याशित है ... – Byson

संबंधित मुद्दे