2013-06-10 8 views
12

मैं एक अपेक्षाकृत सरल समारोह जो का उपयोग करता है एक foreachपीएचपी traversable प्रकार संकेत

function foo($t) { 
    $result; 
    foreach($t as $val) { 
     $result = dosomething($result, $val); 
    } 
    return $result; 
} 

मैं संकेत टाइप करने के लिए करना चाहते हैं, और Traversable मैं

function foo(Traversable $t) { 

जरूरत है हालांकि, ठीक वैसी ही संकेत हो रहा है यह एक सरणी का उपयोग करते समय E_RECOVERABLE_ERROR देता है (जो foreach में उपयोग करने योग्य है): example

Argument 1 passed to foo() must implement interface Traversable, array given 

क्या संकेत टाइप करने का कोई तरीका है या यह संभव नहीं है?

+0

मैनुअल (आपके द्वारा पोस्ट किया गया लिंक): 'सार आधार इंटरफ़ेस जिसे अकेले लागू नहीं किया जा सकता है। इसके बजाय इसे इटरेटरएग्रेगेट या इटरेटर द्वारा कार्यान्वित किया जाना चाहिए। – alfasin

+0

मेरा मानना ​​है कि आप वास्तव में संकेत के रूप में 'सरणी' का उपयोग कर सकते हैं, मैं अपने सिद्धांत का परीक्षण करूंगा, हां आप – Dale

+0

@alfasin कर सकते हैं और इस तरह के किसी वर्ग को 'इटरेटर' लागू करना भी मेल खाता है 'ट्रैवर्सबल', 'इटरेटर' के रूप में 'ट्रैवर्सबल' का एक उप प्रकार है। बेसिक ओओपी-मैकेनिक्स – dtech

उत्तर

9

पीएचपी 7.1 इस उद्देश्य के, जो दोनों सरणियों और \Traversable के उदाहरण को स्वीकार करता है के लिए iterable type declaration परिचय देता है।

पिछले संस्करणों में, आपको प्रकार की घोषणा को छोड़ना होगा।

8

इस बारे में एक बग है: #41942। 'एक बग नहीं' के रूप में बंद। चूंकि PHP arrays ऑब्जेक्ट्स नहीं हैं, वे एक इंटरफ़ेस को कार्यान्वित नहीं कर सकते हैं और ऐसे में array और Traversable दोनों को संकेत देने का कोई तरीका नहीं है।

आप iterator_to_array, ArrayIterator का उपयोग कर सकते हैं या इस प्रकार के संकेत को छोड़ सकते हैं। ध्यान दें कि iterator_to_array पूरे इटरेटर को एक सरणी में प्रतिलिपि बना सकता है जो इस प्रकार अक्षम हो सकता है।

// These functions are functionally equivalent but do not all accept the same arguments 
function foo(array $a) { foobar($a); } 
function bar(Traversable $a) { foobar($a); } 
function foobar($a) { 
    foreach($a as $key => $value) { 
    } 
} 

$array = array(1,2,3) 
$traversable = new MyTraversableObject(); 

foo($array); 
foo(iterator_to_array($traversable)); 

bar(new ArrayIterator($array)); 
bar($traversable); 

foobar($array); 
foobar($traversable); 
+2

आप ऑब्जेक्ट्स में सरणी को कन्वर्ट करने के लिए 'foo (new ArrayIterator (array (1,2,3))' भी कर सकते हैं। – mAsT3RpEE

2

समस्या यह है कि सरणी कोई वस्तु नहीं है, इसलिए वे एक इंटरफ़ेस को कार्यान्वित नहीं कर सकते हैं। तो आप array और Traversable दोनों संकेतों को टाइप नहीं कर सकते हैं।

+1

क्या अन्य PHP देशी इकाइयां हैं जो 'foreach' में प्रयोग योग्य हैं लेकिन लागू नहीं होती हैं 'ट्रैवर्सबल'? – dtech

+0

नहीं, लेकिन आप अपनी खुद की कक्षा लिख ​​सकते हैं जो' IteratorAggregate' या 'Iterator' लागू करता है, और वे 'ट्रैवर्सबल' – bpoiss

+1

बढ़ाते हैं लेकिन वहां यह है: सभी ऑब्जेक्ट 'foreach' में पुन: प्रयोज्य। यदि ऑब्जेक्ट' ट्रैवर्सबल लागू करता है 'इटरेटर (या समेकित पुनरावर्तक) को उलट दिया जाएगा, अन्यथा वस्तु के सार्वजनिक गुण http://php.net/manual/en/control-structures.foreach.php – pozs

3

वही समस्या। मैंने छोड़ दिया है मैं बस समारोह में सब कुछ मैन्युअल रूप से कोड। आप केवल $traversable के प्रकार प्रदर्शित करने के लिए चाहते हैं

function MyFunction($traversable) 
{ 
    if(!$traversable instanceof Traversable && !is_array($traversable)) 
    { 
     throw new InvalidArgumentException(sprintf(
      'Myfunction($traversable = %s): Invalid argument $traversable.' 
      ,var_export($traversable, true) 
     )); 
    } 
} 

संपादित

:

यह आपको कार्यक्षमता आप चाहते हैं देना चाहिए। और यदि आप बच्चे वर्गों में कार्यक्षमता विरासत में चाहते हैं।

public function MyMethod($traversable) 
{ 
    if(!$traversable instanceof Traversable && !is_array($traversable)) 
    { 
     throw new InvalidArgumentException(sprintf(
      '%s::MyMethod($traversable): Invalid argument $traversable of type `%s`.' 
      ,get_class($this) 
      ,gettype($traversable) 
     )); 
    } 
} 
संबंधित मुद्दे