TL; DR: È possibile definire abstract static
su trait
s, ma internals reputa cattiva pratica e può rimuovere in futuro.
Non ho avuto molta caffeina, ma mi darò un colpo.
Strettamente, abstract
significa che la sottoclasse deve implementare e static
significa codice solo per questa classe specifica. Presi insieme, abstract static
significa "la sottoclasse deve implementare il codice solo per questa specifica classe". Concetti totalmente ortogonali.
Ma ... PHP 5.3+ supporta l'ereditarietà statica grazie a LSB. In pratica, apriamo un po 'la definizione: self
prende la precedente definizione di static, mentre static
diventa "codice per questa classe specifica o una delle sue sottoclassi". La nuova definizione di abstract static
è "la sottoclasse deve implementare il codice per questa classe specifica o una delle sue sottoclassi". Questo può portare ad alcune persone che pensano allo static
in senso stretto, alla confusione. Vedi ad esempio bug #53081.
Cosa rende trait
così speciale da suscitare questo avviso? Beh, date un'occhiata al engine code che implementa l'avviso:
if (ptr->flags & ZEND_ACC_STATIC && (!scope || !(scope->ce_flags & ZEND_ACC_INTERFACE))) {
zend_error(error_type, "Static function %s%s%s() cannot be abstract", scope ? ZSTR_VAL(scope->name) : "", scope ? "::" : "", ptr->fname);
}
Questo codice dice il luogo solo un abstract static
è consentito è all'interno di un interface
. Non è unico per i tratti, è unico per la definizione di abstract static
. Perché? Beh, notare c'è un leggero caso angolo nella nostra definizione:
sub-class must implement code for this specific class or any of its sub-classes
Con questo codice:
abstract class Foo {
abstract public static function get();
}
Tale definizione significa che dovrei in grado di chiamare Foo::get
. Dopotutto lo Foo
è una classe (si veda la parola chiave "classe" lì) e nella definizione rigorosa, get
è pensato per essere implementato in quella classe . Ma chiaramente questo non ha senso, perché, beh, siamo tornati all'ortogonalità della staticità severa.
Se lo provate in PHP, si ottiene l'unica risposta razionale possibile:
Cannot call abstract method Foo::get()
Quindi perché PHP aggiunto eredità statica, deve fare i conti con questi casi d'angolo. Questa è la natura delle caratteristiche. Alcune altre lingue (C#, Java, ecc.) Non presentano questo problema, perché adottano la definizione rigorosa e semplicemente non consentono abstract static
. Per sbarazzarci di questo caso d'angolo e semplificare il motore, potremmo applicare questa regola "abstract static only in interface" in futuro. Quindi, E_STRICT
.
userei un delegato del servizio per risolvere il problema:
I have common method I want to use in several classes. This common method relies on a static method that must be defined externally to the common code.
trait MyTrait
{
public function doSomethingWithSetting() {
$service = new MyService($this);
return $service->doSomethingWithSetting();
}
}
class MyService
{
public function __construct(MyInterface $object) {
$this->object = $object;
}
public function doSomethingWithSetting() {
$setting = $this->object->getSetting();
return $setting;
}
}
sente un po 'di Rube Goldberg però. Probabilmente guarderebbero alla motivazione per la statica e prendere in considerazione la possibilità di ridefinirli.
Ho provato quello che vuoi in php 5.6.10 (CLI) e ha funzionato .. Ti ho sbagliato o lo vuoi per php 5.4? – Mjh
@Mjh: qual è la tua impostazione ['error_reporting'] (https://secure.php.net/manual/en/errorfunc.configuration.php#ini.error-reporting)? Quanto sopra dovrebbe dare luogo ad un errore 'E_STRICT'. – eggyal
Ho impostato 'error_reporting (E_ALL);'. Ho dichiarato un tratto con 'public static static function test();' e ho ottenuto 'PHP Strict Standards: la funzione statica MyTest :: test() non dovrebbe essere astratta nel codice shell php sulla riga 1'. Quando creo una classe che utilizza il tratto e se non implemento il metodo astratto, ottengo l'errore 'PHP Fatal: Class MyTestClass contiene 1 metodo astratto e deve quindi essere dichiarato astratto o implementare i restanti metodi (MyTestClass :: test) nel codice della shell php sulla linea 1'. Questo aiuta affatto? – Mjh