J'ai remarqué que vous ne pouvez pas avoir de constantes abstraites en PHP.
Existe-t-il un moyen de forcer une classe enfant à définir une constante (que je dois utiliser dans l'une des méthodes internes de la classe abstraite)?
Un constant
est un constant
; il n'y a pas de constantes abstract
ou private
dans PHP pour autant que je sache, mais vous pouvez contourner:
Exemple de classe abstraite
abstract class Hello {
const CONSTANT_1 = 'abstract'; // Make Abstract
const CONSTANT_2 = 'abstract'; // Make Abstract
const CONSTANT_3 = 'Hello World'; // Normal Constant
function __construct() {
Enforcer::__add(__CLASS__, get_called_class());
}
}
Cela fonctionnerait bien
class Foo extends Hello {
const CONSTANT_1 = 'HELLO_A';
const CONSTANT_2 = 'HELLO_B';
}
new Foo();
Bar retournerait une erreur
class Bar extends Hello {
const CONSTANT_1 = 'BAR_A';
}
new Bar();
Songo retournerait une erreur
class Songo extends Hello {
}
new Songo();
classe Enforcer
class Enforcer {
public static function __add($class, $c) {
$reflection = new ReflectionClass($class);
$constantsForced = $reflection->getConstants();
foreach ($constantsForced as $constant => $value) {
if (constant("$c::$constant") == "abstract") {
throw new Exception("Undefined $constant in " . (string) $c);
}
}
}
}
Cela peut être un peu un "hack", mais fait le travail avec très peu d'effort, mais juste avec un message d'erreur différent si la constante n'est pas déclarée dans la classe enfant.
Une déclaration constante auto-référentielle est syntaxiquement correcte et analyse sans problème, ne générant une erreur que si cette déclaration est réellement exécutée au moment de l'exécution, donc une déclaration auto-référentielle dans la classe abstraite doit être remplacée chez un enfant sinon, il y aura une erreur fatale: Cannot declare self-referencing constant
.
Dans cet exemple, la classe parent abstraite Foo
force tous ses enfants à déclarer la variable NAME
. Ce code fonctionne correctement, produisant Donald
. Cependant, si la classe enfant Fooling
a pas déclaré la variable, l'erreur fatale serait déclenchée.
<?php
abstract class Foo {
// Self-referential 'abstract' declaration
const NAME = self::NAME;
}
class Fooling extends Foo {
// Overrides definition from parent class
// Without this declaration, an error will be triggered
const NAME = 'Donald';
}
$fooling = new Fooling();
echo $fooling::NAME;
Malheureusement non ... une constante est exactement ce qu'elle dit sur l'étain, constante. Une fois défini, il ne peut pas être redéfini, de cette façon, il est impossible d'exiger sa définition via l'héritage abstrait ou les interfaces de PHP.
Cependant ... vous pouvez vérifier si la constante est définie dans le constructeur de la classe parent. Si ce n'est pas le cas, lancez une exception.
abstract class A
{
public function __construct()
{
if (!defined('static::BLAH'))
{
throw new Exception('Constant BLAH is not defined on subclass ' . get_class($this));
}
}
}
class B extends A
{
const BLAH = 'here';
}
$b = new B();
C'est la meilleure façon de penser à cela à partir de votre description initiale.
Non, mais vous pouvez essayer d'autres méthodes telles que les méthodes abstraites:
abstract class Fruit
{
abstract function getName();
abstract function getColor();
public function printInfo()
{
echo "The {$this->getName()} is {$this->getColor()}";
}
}
class Apple extends Fruit
{
function getName() { return 'Apple'; }
function getColor() { return 'red'; }
//other Apple methods
}
class Banana extends Fruit
{
function getName() { return 'banana'; }
function getColor() { return 'yellow'; }
//other banana methods
}
ou membres statiques:
abstract class Fruit
{
protected static $name;
protected static $color;
public function printInfo()
{
echo "The {static::$name} is {static::$color}";
}
}
class Apple extends Fruit
{
protected static $name = 'Apple';
protected static $color = 'red';
//other Apple methods
}
class Banana extends Fruit
{
protected static $name = 'banana';
protected static $color = 'yellow';
//other banana methods
}
Testé en php 7.2 mais devrait le faire depuis 5.3, vous pouvez utiliser la liaison statique tardive pour archiver ce comportement. Il générera une erreur fatale atteignant la même chose qu'une exception car dans la plupart des cas, vous ne voulez pas gérer les erreurs Fatal lors de l'exécution. Si vous le souhaitez, vous pouvez facilement implémenter un gestionnaire d'erreurs personnalisé.
Donc, ce qui suit fonctionne pour moi:
<?php
abstract class Foo {
public function __construct() {
echo static::BAR;
}
}
class Bar extends Foo {
const BAR = "foo bar";
}
$bar = new Bar(); //foo bar
Si vous supprimez le const
, vous obtiendrez un:
Fatal error: Uncaught Error: Undefined class constant 'BAR' in ...