Khai báo các phương thức phải tương thích với các phương thức gốc trong PHP


107
Tiêu chuẩn nghiêm ngặt: Khai báo của childClass :: customMethod () phải tương thích với khai báo của parentClass :: customMethod ()

Nguyên nhân có thể gây ra lỗi này trong PHP là gì? Tôi có thể tìm thông tin về việc tương thích nghĩa là gì?


notJim đã hoàn toàn đúng. @ Waiwai933, nếu bạn có thể đăng tiêu đề (chỉ dòng đầu tiên function customMethod( ... ):) cho mỗi chức năng, chúng tôi có thể cho bạn biết vấn đề cụ thể
nickf

Chi tiết thêm về thông báo lỗi và hàm ý về thời gian biên dịch PHP: bug.php.net/bug.php?id=46851
hakre


1
Vấn đề của tôi là một đối số đã được gõ gợi ý nhưng sau đó tôi đã không thêm vào use Closure;đầu lớp của mình (vì gợi ý là kiểu Closure). Vì vậy, hãy chắc chắn kiểm tra xem bạn có thiếu các phụ thuộc như vậy không.
Ryan

Câu trả lời:


126

childClass::customMethod()có các đối số khác nhau hoặc cấp độ truy cập (công khai / riêng tư / bảo vệ) khác với parentClass::customMethod().


1
lẽ của nó bởi vì tầm nhìn chữ ký, phương pháp không phải là một vấn đề trong PHP
Gabriel Sosa

43
Việc có các giá trị mặc định đối số chính xác giống nhau cũng rất quan trọng. Ví dụ, parentClass::customMethod($thing = false)childClass::customMethod($thing)sẽ gây ra lỗi, bởi vì phương thức của con chưa xác định giá trị mặc định cho đối số đầu tiên.
Charles

1
Tôi tin rằng khả năng hiển thị thực sự là một lỗi khác. Nhân tiện, tại cửa hàng của tôi, chúng tôi không sử dụng chế độ nghiêm ngặt, vì điều này (chúng tôi sử dụng E_ALL, IIRC).
davidtbernal

12
Điều này đã thay đổi trong PHP 5.4, btw: * E_ALL hiện bao gồm các lỗi cấp E_STRICT trong chỉ thị cấu hình error_reporting. Xem tại đây: php.net/manual/en/migration54.other.php
Duncan Lock

1
Thiếu dấu và ( &) trong các đối số cũng có thể gây ra lỗi này.
IvanRF

36

Thông báo này có nghĩa là có một số cuộc gọi phương thức có thể không thực hiện được tại thời điểm chạy. Giả sử bạn có

class A { public function foo($a = 1) {;}}
class B extends A { public function foo($a) {;}}
function bar(A $a) {$a->foo();}

Trình biên dịch chỉ kiểm tra lệnh gọi $ a-> foo () so với các yêu cầu của A :: foo () không yêu cầu tham số. Tuy nhiên, $ a có thể là một đối tượng của lớp B yêu cầu một tham số và do đó, cuộc gọi sẽ thất bại trong thời gian chạy.

Tuy nhiên, điều này không bao giờ có thể thất bại và không gây ra lỗi

class A { public function foo($a) {;}}
class B extends A { public function foo($a = 1) {;}}
function bar(A $a) {$a->foo();}

Vì vậy, không phương thức nào có thể có nhiều tham số bắt buộc hơn phương thức mẹ của nó.

Thông báo tương tự cũng được tạo ra khi các gợi ý kiểu không khớp, nhưng trong trường hợp này PHP thậm chí còn hạn chế hơn. Điều này gây ra lỗi:

class A { public function foo(StdClass $a) {;}}
class B extends A { public function foo($a) {;}}

như thế này:

class A { public function foo($a) {;}}
class B extends A { public function foo(StdClass $a) {;}}

Điều đó có vẻ hạn chế hơn mức cần thiết và tôi cho rằng đó là do nội bộ.

Sự khác biệt về khả năng hiển thị gây ra một lỗi khác, nhưng vì lý do cơ bản giống nhau. Không có phương thức nào có thể ít hiển thị hơn phương thức mẹ của nó.


2
trong ví dụ cuối cùng của bạn - sẽ không có lỗi ở đây vì nó hợp pháp, stdClass $ a hạn chế hơn so với hỗn hợp $ a. có cách nào để giải quyết vấn đề này không? ý tôi là trong trường hợp này PHP nên cho phép điều này nhưng nó vẫn báo lỗi ...
galchen

2
Ví dụ cuối cùng của bạn là kiểu an toàn, vì vậy nó chắc chắn "hạn chế hơn mức cần thiết". Đây có thể là một trường hợp lập trình sùng bái hàng hóa, vì nó xung đột với tính đa hình trong C ++ và Java en.wikipedia.org/wiki/…
Warbo

cảm ơn vì đã giải thích, trong trường hợp của tôi, ví dụ đầu tiên mà bạn đưa ra chính xác là nguyên nhân gây ra lỗi của tôi.
billynoah

Cảm ơn vì điều này, thưa ông.
Eldoïr

22

nếu bạn muốn giữ biểu mẫu OOP mà không tắt bất kỳ lỗi nào, bạn cũng có thể:

class A
{
    public function foo() {
        ;
    }
}
class B extends A
{
    /*instead of : 
    public function foo($a, $b, $c) {*/
    public function foo() {
        list($a, $b, $c) = func_get_args();
        // ...

    }
}

Tôi rất thích sử dụng bản hack này để khắc phục những lỗi này. Tôi lo lắng rằng có thể có một hình phạt hiệu suất đối với cách tiếp cận này? Tôi sẽ nghiên cứu vấn đề này nhưng nếu bạn có bất kỳ tài nguyên nào để giúp trả lời câu hỏi đó, điều đó thật tuyệt.
Adam Friedman

Tùy thuộc vào tình huống mà tôi đoán. Vẫn có, nó có thể là một chút hacky, nhưng nó là php? đã, đôi khi đó có thể là một công việc tốt đẹp, cảm ơn! <@
Master James

bạn đã cứu ngày của tôi! đây là lựa chọn duy nhất để khởi chạy dự án php5 cũ trên máy chủ với php7 mà không bị đau
vladkras

Đối với trường hợp này, bạn có thể sử dụng các giá trị mặc định thay vì func_get_args(), ví dụ, trong B, public function foo($a = null, $b = null, $c = null), vì điều này không phá vỡ hợp đồng hứa A.
Jake

1

Chỉ để mở rộng lỗi này trong ngữ cảnh của một giao diện, nếu bạn đang nhập gợi ý các tham số chức năng của bạn như vậy:

giao diện A

use Bar;

interface A
{
    public function foo(Bar $b);
}

Hạng B

class B implements A
{
    public function foo(Bar $b);
}

Nếu bạn đã quên đưa usecâu lệnh vào lớp triển khai của mình (Lớp B), thì bạn cũng sẽ gặp lỗi này mặc dù các tham số phương thức giống hệt nhau.


0

Tôi đã gặp phải sự cố này khi cố gắng mở rộng một lớp hiện có từ GitHub. Tôi sẽ cố gắng giải thích bản thân mình, đầu tiên là viết về lớp học như tôi nghĩ, và sau đó là lớp học như bây giờ.

Những gì tôi mặc dù

namespace mycompany\CutreApi;

use mycompany\CutreApi\ClassOfVendor;

class CutreApi extends \vendor\AwesomeApi\AwesomeApi
{
   public function whatever(): ClassOfVendor
   {
        return new ClassOfVendor();
   }
}

Cuối cùng tôi đã làm được gì

namespace mycompany\CutreApi;

use \vendor\AwesomeApi\ClassOfVendor;

class CutreApi extends \vendor\AwesomeApi\AwesomeApi
{
   public function whatever(): ClassOfVendor
   {
        return new \mycompany\CutreApi\ClassOfVendor();
   }
}

Vì vậy, có vẻ như lỗi này cũng xuất hiện khi bạn đang sử dụng một phương thức trả về một lớp có không gian tên và bạn cố gắng trả về cùng một lớp nhưng với không gian tên khác. May mắn thay, tôi đã tìm thấy giải pháp này, nhưng tôi không hiểu đầy đủ lợi ích của tính năng này trong php 7.2, đối với tôi, việc viết lại các phương thức lớp hiện có là điều bình thường khi bạn cần, bao gồm việc xác định lại các tham số đầu vào và / hoặc thậm chí hành vi của phương pháp.

Một nhược điểm của aproach trước đó là IDE không thể nhận ra các phương thức mới được triển khai trong \ mycompany \ CutreApi \ ClassOfVendor (). Vì vậy, bây giờ, tôi sẽ đi với triển khai này.

Hiện đã xong

namespace mycompany\CutreApi;

use mycompany\CutreApi\ClassOfVendor;

class CutreApi extends \vendor\AwesomeApi\AwesomeApi
{
   public function getWhatever(): ClassOfVendor
   {
        return new ClassOfVendor();
   }
}

Vì vậy, thay vì cố gắng sử dụng phương pháp "bất cứ điều gì", tôi đã viết một phương thức mới có tên "getW Anything". Trên thực tế, cả hai đều làm như nhau, chỉ trả về một lớp, nhưng với các không gian tên khác nhau như tôi đã mô tả trước đây.

Hy vọng điều này có thể giúp một ai đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.