Constantes abstractas en PHP-Forzar a una clase hija a definir una constante


He notado que no se pueden tener constantes abstractas en PHP.

¿Hay alguna manera de forzar a una clase hija a definir una constante (que necesito usar en uno de los métodos internos de la clase abstracta) ?

Author: Jon Surrell, 2012-04-29

4 answers

A constant es a constant; no hay abstract o private constantes en PHP hasta donde sé, pero puedes tener un trabajo alrededor:

Ejemplo De Clase Abstracta

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());
    }
}

Esto funcionaría bien

class Foo extends Hello {
    const CONSTANT_1 = 'HELLO_A';
    const CONSTANT_2 = 'HELLO_B';
}
new Foo();

Bar devolvería Error

class Bar extends Hello {
    const CONSTANT_1 = 'BAR_A';
}
new Bar();

Songo devolvería Error

class Songo extends Hello {

}
new Songo();

Enforcer Class

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);
            }
        }
    }
}
 25
Author: Baba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-25 09:26:22

Esto puede ser un poco 'hack', pero hace el trabajo con muy poco esfuerzo, pero solo con un mensaje de error diferente si la constante no se declara en la clase hija.

Una declaración de constante autorreferencial es sintácticamente correcta y analiza sin problema, solo lanzando un error si esa declaración se ejecuta realmente en tiempo de ejecución, por lo que una declaración autorreferencial en la clase abstracta debe ser anulada en una clase hija, de lo contrario habrá un error fatal: Cannot declare self-referencing constant.

En este ejemplo, la clase padre abstracta Foo fuerza a todos sus hijos a declarar la variable NAME. Este código funciona bien, produciendo Donald. Sin embargo, si la clase hija Fooling hizo no declarar la variable, se activaría el error fatal.

<?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;
 20
Author: WebSmithery,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-31 07:26:59

Desafortunadamente no... una constante es exactamente lo que dice en la lata, constante. Una vez definido no puede ser redefinido, por lo que de esa manera, es imposible requerir su definición a través de la herencia abstracta o interfaces de PHP.

Sin embargo... puede comprobar si la constante está definida en el constructor de la clase padre. Si no lo hace, lanza una excepción.

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

Esta es la mejor manera que puedo pensar de hacer esto desde su descripción inicial.

 15
Author: Jamie Rumbelow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-29 00:24:27

No, sin embargo, podría probar otras formas como métodos abstractos:

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
}  

O miembros estáticos:

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
} 

Fuente

 7
Author: Songo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-04 11:31:55