2013-06-10 45 views
12

Tôi có một chức năng tương đối đơn giản trong đó sử dụng một foreachPHP loại traversable gợi ý

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

Tôi muốn gõ gợi ý, và Traversable có vẻ là kiểu gợi ý chính xác tôi cần

function foo(Traversable $t) { 

Tuy nhiên điều này cung cấp cho một E_RECOVERABLE_ERROR khi sử dụng một mảng (tất nhiên là có thể sử dụng được trong một số foreach): example

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

Có cách nào để nhập gợi ý hoặc điều này là không thể?

+0

Từ hướng dẫn (liên kết mà bạn đã đăng): 'Giao diện cơ bản trừu tượng không thể được triển khai một mình. Thay vào đó nó phải được thực hiện bởi IteratorAggregate hoặc Iterator.' – alfasin

+0

Tôi tin rằng bạn thực sự có thể sử dụng 'mảng' làm gợi ý, tôi sẽ kiểm tra lý thuyết của tôi, có bạn có thể – Dale

+0

@alfasin Và như vậy bất kỳ lớp nào thực hiện' Iterator' cũng sẽ khớp 'Traversable', như' Iterator' là một kiểu con của 'Traversable'. Cơ bản OOP-cơ học – dtech

Trả lời

9

PHP 7.1 giới thiệu các iterable type declaration cho mục đích này, mà chấp nhận cả hai mảng và trường hợp của \Traversable.

Trong các phiên bản trước, bạn sẽ phải bỏ qua khai báo loại.

8

Có lỗi về việc này: #41942. Đã đóng thành 'không phải lỗi'. Vì các mảng PHP không phải là các đối tượng mà chúng không thể thực hiện một giao diện và do đó không có cách nào để nhập gợi ý cả arrayTraversable.

Bạn có thể sử dụng iterator_to_array, ArrayIterator hoặc bỏ qua gợi ý loại. Lưu ý rằng iterator_to_array sẽ sao chép toàn bộ vòng lặp vào một mảng do đó có thể không hiệu quả.

// 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

Bạn cũng có thể làm 'foo (new ArrayIterator (array (1,2,3))' để chuyển mảng thành các đối tượng – mAsT3RpEE

2

Vấn đề là, mảng không có đối tượng, vì vậy chúng không thể triển khai giao diện. Vì vậy, bạn không thể nhập gợi ý cả, arrayTraversable.

+1

Có các thực thể gốc PHP nào khác có thể sử dụng trong 'foreach' nhưng không thực hiện 'Traversable'? – dtech

+0

Không, nhưng bạn có thể viết lớp của riêng bạn thực hiện' IteratorAggregate' hoặc 'Iterator', và chúng mở rộng' Traversable' – bpoiss

+1

Nhưng có: tất cả các đối tượng có thể lặp lại trong 'foreach'. 'trình lặp (hoặc trình lặp tổng hợp) sẽ được duyệt qua, các thuộc tính công khai của đối tượng http://php.net/manual/en/control-structures.foreach.php – pozs

3

Cùng một vấn đề. Tôi đã từ bỏ tôi chỉ cần tự mã hóa mọi thứ trong hàm.

này nên cung cấp cho bạn các chức năng bạn muốn:

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

EDIT

Nếu bạn chỉ muốn hiển thị loại $traversable. Và nếu bạn muốn các chức năng có thể kế thừa trong các lớp con.

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) 
     )); 
    } 
} 
Các vấn đề liên quan