Yöntem Bildirimi PHP'deki Ana Yöntemlerle Uyumlu Olmalıdır


107
Katı Standartlar: childClass :: customMethod () bildirimi parentClass :: customMethod () ile uyumlu olmalıdır

PHP'deki bu hatanın olası nedenleri nelerdir? Uyumlu olmanın ne anlama geldiğiyle ilgili bilgiyi nerede bulabilirim ?


notJim tam olarak haklı. @ waiwai933, function customMethod( ... )her işlev için başlıkları gönderebilirseniz (yalnızca ilk satır
:)

Hata mesajı ve PHP derleme zamanı etkileri hakkında daha fazla ayrıntı: bugs.php.net/bug.php?id=46851
hakre


1
Benim sorunum, bir argümanın tip ipucu olmasıydı, ancak daha sonra use Closure;sınıfımın en üstüne eklememiştim (tip ipucu olduğundan Closure). Öyleyse ... bunun gibi bağımlılıkların eksik olup olmadığını kontrol ettiğinizden emin olun.
Ryan

Yanıtlar:


126

childClass::customMethod()farklı argümanlara veya farklı bir erişim düzeyine (genel / özel / korumalı) sahiptir parentClass::customMethod().


1
Muhtemelen görünürlük , yöntem imzası PHP'de bir sorun olmadığı içindir
Gabriel Sosa

43
Aynı bağımsız değişken varsayılan değerlerine sahip olmak da önemlidir. Örneğin, parentClass::customMethod($thing = false)ve childClass::customMethod($thing)hatayı tetikler çünkü çocuğun yöntemi ilk bağımsız değişken için varsayılan bir değer tanımlamamıştır.
Charles

1
Görünürlüğün aslında farklı bir hata olduğuna inanıyorum. Bu arada, mağazamda bu nedenle katı modu kullanmıyoruz (E_ALL, IIRC kullanıyoruz).
davidtbernal

12
Bu PHP 5.4'te değişti, btw: * E_ALL artık error_reporting yapılandırma yönergesinde E_STRICT düzeyinde hatalar içeriyor. Buraya bakın: php.net/manual/en/migration54.other.php
Duncan Lock

1
&Bağımsız değişkenlerde bir ve işareti ( ) olmaması da bu hatayı tetikleyebilir.
IvanRF

36

Bu mesaj, çalışma zamanında başarısız olabilecek bazı olası yöntem çağrıları olduğu anlamına gelir. Varsayalım ki

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

Derleyici sadece $ a-> foo () çağrısını parametre gerektirmeyen A :: foo () gereksinimlerine göre kontrol eder. Ancak $ a, bir parametre gerektiren B sınıfının bir nesnesi olabilir ve bu nedenle çağrı çalışma zamanında başarısız olur.

Ancak bu asla başarısız olmaz ve hatayı tetiklemez

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

Bu nedenle hiçbir yöntemin üst yönteminden daha fazla gerekli parametresi olamaz.

Aynı mesaj, tür ipuçları eşleşmediğinde de oluşturulur, ancak bu durumda PHP daha da kısıtlayıcıdır. Bu bir hata verir:

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

bunun gibi:

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

Bu olması gerekenden daha kısıtlayıcı görünüyor ve sanırım içsel konulardan kaynaklanıyor.

Görünürlük farklılıkları farklı bir hataya neden olur, ancak aynı temel nedenden dolayı. Hiçbir yöntem, ana yönteminden daha az görünür olamaz.


2
son örneğinizde - burada bir hata olmamalı çünkü okunaklı, stdClass $ a, karışık $ a'dan daha kısıtlayıcı. Bunu aşmanın bir yolu var mı? Demek istediğim, bu durumda PHP buna izin vermeli ama yine de bir hata veriyor ...
galchen

2
Son örneğiniz tür açısından güvenlidir, bu nedenle kesinlikle "olması gerekenden daha kısıtlayıcıdır". Bu, C ++ ve Java'daki polimorfizm ile çeliştiği için bir kargo kült programlama durumu olabilir en.wikipedia.org/wiki/…
Warbo

açıklama için teşekkürler, benim durumumda verdiğiniz ilk örnek tam olarak benim hatamı tetikleyen şeydi.
billynoah

Bunun için teşekkür ederim efendim.
Eldoïr

22

OOP formunu herhangi bir hatayı kapatmadan tutmak istiyorsanız, şunları da yapabilirsiniz:

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

    }
}

Bu hataların üstesinden gelmek için bu hack'i kullanmayı çok isterim. Bu yaklaşımın bir performans cezası olabileceğinden endişeleniyorum. Bunu araştıracağım, ancak bu soruyu yanıtlamaya yardımcı olacak herhangi bir kaynağınız varsa, bu harika olur.
Adam Friedman

Sanırım duruma bağlı. Yine de Evet, belki biraz hantal, ama php? zaten, bazen bu iyi bir çalışma olabilir, teşekkürler! <@
Usta James

günümü kurtardın! bu, sunucuda eski php5 projesini ağrısız php7 ile başlatmak için tek seçenekti
vladkras

Bu durum için yerine varsayılan değerleri kullanabilirsiniz func_get_args()yani içinde, B, public function foo($a = null, $b = null, $c = null), bu sonu yok olarak sözleşme ile söz A.
Jake

1

Sadece bu hatayı bir arayüz bağlamında genişletmek için, eğer fonksiyon parametrelerinizi şu şekilde ipucu olarak yazıyorsanız:

arayüz A

use Bar;

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

B sınıfı

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

İfadeyi useuygulama sınıfınıza (Sınıf B) eklemeyi unuttuysanız , yöntem parametreleri aynı olsa bile bu hatayı da alırsınız.


0

GitHub'dan mevcut bir sınıfı genişletmeye çalışırken bu sorunla karşılaştım. Kendimi açıklamaya çalışacağım, önce sınıfı olması gerektiği gibi yazacağım, sonra da şimdi olduğu gibi.

Ne düşündüm

namespace mycompany\CutreApi;

use mycompany\CutreApi\ClassOfVendor;

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

Sonunda ne yaptım

namespace mycompany\CutreApi;

use \vendor\AwesomeApi\ClassOfVendor;

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

Görünüşe göre bu hata, isim alanlı bir sınıf döndüren bir yöntem kullandığınızda ve aynı sınıfı başka bir ad alanıyla döndürmeye çalıştığınızda da ortaya çıkıyor. Neyse ki bu çözümü buldum, ancak php 7.2'de bu özelliğin faydasını tam olarak anlamıyorum, benim için mevcut sınıf yöntemlerini ihtiyaç duyduğunuzda yeniden yazmak normaldir, buna girdi parametrelerinin yeniden tanımlanması ve / veya hatta davranış yöntem.

Önceki yaklaşımın bir dezavantajı, IDE'lerin \ sirketim \ CutreApi \ ClassOfVendor () içinde uygulanan yeni yöntemleri tanıyamamasıdır. O yüzden şimdilik bu uygulamaya geçeceğim.

Şu anda yapıldı

namespace mycompany\CutreApi;

use mycompany\CutreApi\ClassOfVendor;

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

Bu yüzden, "her neyse" yöntemini kullanmaya çalışmak yerine, "getWhatever" adında yeni bir yöntem yazdım. Aslında ikisi de aynı şeyi yapıyor, sadece bir sınıfı geri veriyorlar, ama daha önce anlattığım gibi farklı ad alanları ile.

Umarım bu birine yardımcı olabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.