2016-08-21 18 views
34

Tôi đã gặp phải vấn đề với việc sử dụng gợi ý kiểu trả về trong PHP 7. Sự hiểu biết của tôi là gợi ý : self có nghĩa là bạn dự định cho lớp triển khai tự trả về. Vì vậy, tôi đã sử dụng : self trong giao diện của mình để chỉ ra rằng, nhưng khi tôi cố thực sự triển khai giao diện, tôi gặp phải các lỗi tương thích.Giao diện PHP 7, trả về kiểu gợi ý và tự

Sau đây là một cuộc biểu tình đơn giản về vấn đề này tôi đã chạy vào:

interface iFoo 
{ 
    public function bar (string $baz) : self; 
} 

class Foo implements iFoo 
{ 

    public function bar (string $baz) : self 
    { 
     echo $baz . PHP_EOL; 
     return $this; 
    } 
} 

(new Foo()) -> bar ("Fred") 
    -> bar ("Wilma") 
    -> bar ("Barney") 
    -> bar ("Betty"); 

Sản lượng dự kiến ​​là:

Fred Wilma Barney Betty

Những gì tôi thực sự nhận được là:

PHP Fatal error: Declaration of Foo::bar(int $baz): Foo must be compatible with iFoo::bar(int $baz): iFoo in test.php on line 7

Điều là Foo là một thực hiện của iFoo, vì vậy theo như tôi có thể nói việc thực hiện nên được hoàn hảo comp với giao diện đã cho. Tôi có thể sửa chữa vấn đề này bằng cách thay đổi giao diện hoặc lớp thực hiện (hoặc cả hai) để trả về giao diện bằng tên thay vì sử dụng self, nhưng hiểu biết của tôi là ngữ nghĩa self có nghĩa là "trả về cá thể của lớp bạn vừa gọi phương pháp trên ". Do đó việc thay đổi nó thành giao diện sẽ có nghĩa là trong lý thuyết rằng tôi có thể trả về bất kỳ thể hiện của một cái gì đó thực hiện giao diện khi ý định của tôi là cho thể hiện được gọi là cái sẽ được trả về.

Đây có phải là sự giám sát trong PHP hay đây là quyết định thiết kế có chủ ý không? Nếu đó là trước đây là có bất kỳ cơ hội nhìn thấy nó cố định trong PHP 7.1? Nếu không thì cách trả về gợi ý chính xác là giao diện của bạn mong đợi bạn trả về cá thể bạn vừa gọi là phương thức cho chuỗi là gì?

+0

Tôi nghĩ rằng đó là lỗi trong PHP trả về loại gợi ý, có lẽ bạn nên tăng nó thành [bug] (https://bugs.php.net/); nhưng bất kỳ bản sửa lỗi nào cũng không thể vào được bản 7.1 7.1 ở giai đoạn cuối này –

+0

Vì phiên bản beta cuối cùng 7.1 đã được đưa lên mạng cách đây vài ngày, rất khó có thể sửa được 7.1. –

+0

Không quan tâm, bạn đang đọc giải thích cách thức kiểu trả về 'self' được cho là hoạt động như thế nào? –

Trả lời

37

self không đề cập đến trường hợp, nó đề cập đến lớp hiện tại. Không có cách nào để một giao diện chỉ định rằng cùng một đối tượng phải được trả lại - bằng cách sử dụng self theo cách bạn đang cố gắng sẽ chỉ thực thi rằng thể hiện được trả lại là của cùng một lớp.

Điều đó nói rằng, khai báo kiểu trả về trong PHP phải là bất biến trong khi những gì bạn đang cố gắng là biến đổi.

Việc bạn sử dụng self tương đương với:

interface iFoo 
{ 
    public function bar (string $baz) : iFoo; 
} 

class Foo implements iFoo 
{ 

    public function bar (string $baz) : Foo {...} 
} 

mà không được phép.


Các Return Type Declarations RFCthis to say:

The enforcement of the declared return type during inheritance is invariant; this means that when a sub-type overrides a parent method then the return type of the child must exactly match the parent and may not be omitted. If the parent does not declare a return type then the child is allowed to declare one.

...

This RFC originally proposed covariant return types but was changed to invariant because of a few issues. It is possible to add covariant return types at some point in the future.


Đối với thời điểm hiện tại ít nhất là tốt nhất bạn có thể làm là:

interface iFoo 
{ 
    public function bar (string $baz) : iFoo; 
} 

class Foo implements iFoo 
{ 

    public function bar (string $baz) : iFoo {...} 
} 
+2

Điều đó nói rằng, tôi đã có thể mong đợi một kiểu trả về 'static' để làm việc, nhưng nó thậm chí không được công nhận –

+0

Tôi đã tìm ra Tôi sẽ, tuy nhiên, đã ưa thích chỉ sử dụng: tự nếu có thể bởi vì nếu một lớp học đang thực hiện một giao diện thì giá trị trả về của bản thân là hoàn toàn – GordonM

+6

Paul, xóa các bình luận bạn đã xóa ở đây thực sự có hại vì (A) nó mất thông tin quan trọng và (B) nó phá vỡ luồng thảo luận liên quan đến các nhận xét khác Tôi không thể thấy bất kỳ lý do gì khiến các bình luận của bạn dựa vào Mark và Gordon cần phải được xóa bỏ. Trên thực tế, bạn đang làm điều này khắp nơi, và nó cần phải dừng lại. một câu hỏi cũ và xóa tất cả nhận xét của bạn s, phá hủy hoàn toàn luồng thảo luận. Trong thực tế, nó có hại và gây rối. –

0

này trông giống như hành vi mong đợi đối với tôi .

Chỉ cần thay đổi phương thức Foo::bar của bạn để trả lại iFoo thay vì self và được thực hiện với nó.

Giải thích:

self như được sử dụng trong giao diện có nghĩa là "một đối tượng kiểu iFoo."
self như được sử dụng trong việc triển khai có nghĩa là "một đối tượng thuộc loại Foo".

Do đó, các loại trả về trong giao diện và triển khai rõ ràng là không giống nhau.

Một trong các nhận xét đề cập đến Java và bạn có gặp vấn đề này hay không. Câu trả lời là có, bạn sẽ có cùng một vấn đề nếu Java cho phép bạn viết mã như thế - mà nó không có. Vì Java yêu cầu bạn sử dụng tên của loại thay vì lối tắt self của PHP, bạn sẽ không bao giờ thực sự thấy điều này. (Xem here cho một cuộc thảo luận về một tương tự vấn đề trong Java.)

+0

Vì vậy, khai báo 'self', tương tự như khai báo' MyClass :: class'? – peter

+1

@Laser Vâng, đúng vậy. –

+1

Nhưng nếu Foo thực hiện iFoo thì Foo theo định nghĩa của loại iFoo – GordonM

3

Nó cũng có thể là một giải pháp, mà bạn không xác định rõ kiểu dữ liệu trở lại trong giao diện, chỉ trong PHPDoc và sau đó bạn có thể định nghĩa loại trả lại nhất định trong việc triển khai:

interface iFoo 
{ 
    public function bar (string $baz); 
} 

class Foo implements iFoo 
{ 
    public function bar (string $baz) : Foo {...} 
} 
Các vấn đề liên quan