Deklarasi Metode harus Kompatibel dengan Metode Induk di PHP

107
Standar Ketat: Deklarasi childClass :: customMethod () harus kompatibel dengan parentClass :: customMethod ()

Apa kemungkinan penyebab kesalahan ini di PHP? Di mana saya dapat menemukan informasi tentang apa artinya menjadi kompatibel ?

waiwai933
sumber
notJim benar. @ waiwai933, jika Anda dapat memposting tajuk (hanya baris pertama :) function customMethod( ... )untuk setiap fungsi kami dapat memberi tahu Anda masalah spesifiknya
nickf
Rincian lebih lanjut tentang pesan kesalahan dan implikasi waktu kompilasi PHP: bugs.php.net/bug.php?id=46851
hakre
1
Masalah saya adalah bahwa sebuah argumen diisyaratkan dengan tipe tetapi kemudian saya tidak menambahkan use Closure;ke atas di kelas saya (karena petunjuk tipe itu Closure). Jadi ... pastikan untuk memeriksa apakah Anda kehilangan dependensi seperti itu.
Ryan

Jawaban:

126

childClass::customMethod()memiliki argumen yang berbeda, atau tingkat akses yang berbeda (publik / pribadi / dilindungi) dari parentClass::customMethod().

davidtbernal.dll
sumber
1
mungkin karena visibilitas , tanda tangan metode tidak menjadi masalah di PHP
Gabriel Sosa
43
Memiliki nilai default argumen yang sama persis juga penting. Misalnya, parentClass::customMethod($thing = false)dan childClass::customMethod($thing)akan memicu kesalahan, karena metode anak belum menentukan nilai default untuk argumen pertama.
Charles
1
Saya percaya visibilitas sebenarnya adalah kesalahan yang berbeda. Ngomong-ngomong, di toko saya kami tidak menggunakan mode ketat, karena ini (kami menggunakan E_ALL, IIRC).
davidtbernal
12
Ini telah berubah di PHP 5.4, btw: * E_ALL sekarang menyertakan kesalahan level E_STRICT dalam arahan konfigurasi error_reporting. Lihat di sini: php.net/manual/en/migration54.other.php
Duncan Lock
1
Tanda ampersand ( &) yang hilang dalam argumen juga dapat memicu kesalahan ini.
IvanRF
36

Pesan ini berarti bahwa ada pemanggilan metode tertentu yang mungkin gagal pada saat run-time. Misalkan Anda punya

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

Kompilator hanya memeriksa panggilan $ a-> foo () terhadap persyaratan A :: foo () yang tidak memerlukan parameter. Namun $ a dapat menjadi objek kelas B yang membutuhkan parameter sehingga panggilan akan gagal saat runtime.

Namun ini tidak akan pernah gagal dan tidak memicu kesalahan

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

Jadi tidak ada metode yang memiliki lebih banyak parameter yang diperlukan selain metode induknya.

Pesan yang sama juga dihasilkan ketika petunjuk tipe tidak cocok, tetapi dalam kasus ini PHP bahkan lebih membatasi. Ini memberikan kesalahan:

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

seperti ini:

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

Itu tampaknya lebih ketat daripada yang seharusnya dan saya berasumsi itu karena internal.

Perbedaan visibilitas menyebabkan kesalahan yang berbeda, tetapi untuk alasan dasar yang sama. Tidak ada metode yang kurang terlihat dari metode induknya.

ldrut
sumber
2
dalam contoh terakhir Anda - seharusnya tidak ada kesalahan di sini karena ini sah, stdClass $ a lebih ketat daripada campuran $ a. apakah ada cara untuk menyiasatinya? maksud saya dalam hal ini PHP harus mengizinkan ini tetapi masih memberikan kesalahan ...
galchen
2
Contoh terakhir Anda adalah type-safe, jadi ini pasti "lebih membatasi daripada yang seharusnya". Ini mungkin kasus pemrograman kultus kargo, karena bertentangan dengan polimorfisme di C ++ dan Java en.wikipedia.org/wiki/…
Warbo
terima kasih atas penjelasannya, dalam kasus saya contoh pertama yang Anda berikan persis seperti yang memicu kesalahan saya.
billynoah
Terima kasih untuk ini, tuan.
Eldoïr
22

jika Anda ingin menyimpan formulir OOP tanpa mematikan kesalahan, Anda juga dapat:

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();
        // ...

    }
}
Sajjad Shirazy
sumber
Saya ingin sekali menggunakan peretasan ini untuk mengatasi kesalahan ini. Saya khawatir mungkin ada penalti kinerja untuk pendekatan ini? Saya akan meneliti ini tetapi jika Anda memiliki sumber daya untuk membantu menjawab pertanyaan itu, itu akan bagus.
Adam Friedman
Tergantung situasinya, kurasa. Masih Ya mungkin agak hacky, tapi itu php? terkadang itu bisa menjadi solusi yang bagus, terima kasih! <@
Master James
kamu menyelamatkan hariku! ini adalah satu-satunya pilihan untuk meluncurkan proyek php5 lama di server dengan php7 tanpa rasa sakit
vladkras
Untuk hal ini Anda dapat menggunakan nilai default, bukan func_get_args(), yaitu, di B, public function foo($a = null, $b = null, $c = null), karena hal ini tidak melanggar kontrak yang dijanjikan oleh A.
Jake
1

Hanya untuk memperluas kesalahan ini dalam konteks antarmuka, jika Anda mengetik mengisyaratkan parameter fungsi Anda seperti:

antarmuka A

use Bar;

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

Kelas B

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

Jika Anda lupa untuk menyertakan usepernyataan pada kelas implementasi Anda (Kelas B), Anda juga akan mendapatkan kesalahan ini meskipun parameter metode identik.

Spholt
sumber
0

Saya menghadapi masalah ini saat mencoba memperluas kelas yang ada dari GitHub. Saya akan mencoba menjelaskan diri saya sendiri, pertama menulis kelas sebagaimana saya seharusnya, dan kemudian kelas seperti sekarang.

Apa yang saya pikirkan

namespace mycompany\CutreApi;

use mycompany\CutreApi\ClassOfVendor;

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

Apa yang akhirnya saya lakukan

namespace mycompany\CutreApi;

use \vendor\AwesomeApi\ClassOfVendor;

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

Jadi tampaknya errror ini muncul juga saat Anda menggunakan metode yang mengembalikan kelas dengan namespace, dan Anda mencoba mengembalikan kelas yang sama tetapi dengan namespace lain. Untungnya saya telah menemukan solusi ini, tetapi saya tidak sepenuhnya memahami manfaat dari fitur ini di php 7.2, bagi saya itu normal untuk menulis ulang metode kelas yang ada saat Anda membutuhkannya, termasuk redefinisi parameter input dan / atau bahkan perilaku metode.

Satu kelemahan pendekatan sebelumnya, adalah bahwa IDE tidak dapat mengenali metode baru yang diterapkan di \ mycompany \ CutreApi \ ClassOfVendor (). Jadi, untuk saat ini, saya akan melakukan implementasi ini.

Saat ini selesai

namespace mycompany\CutreApi;

use mycompany\CutreApi\ClassOfVendor;

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

Jadi, alih-alih mencoba menggunakan metode "terserah", saya menulis metode baru yang disebut "getWhatever". Faktanya keduanya melakukan hal yang sama, hanya mengembalikan kelas, tetapi dengan ruang nama yang berbeda seperti yang saya jelaskan sebelumnya.

Semoga ini bisa membantu seseorang.

Ferran
sumber