Abstrakcyjne stałe w PHP-zmuszają klasę potomną do zdefiniowania stałej

Zauważyłem, że w PHP nie można mieć stałych abstrakcyjnych.

Czy istnieje sposób, w jaki mogę zmusić klasę potomną do zdefiniowania stałej (którą muszę użyć w jednej z wewnętrznych metod klasy abstrakcyjnej) ?

Author: Jon Surrell, 2012-04-29

4 answers

A constant jest constant; nie ma abstract lub private stałych w PHP, o ile wiem, ale możesz mieć pracę wokół:

Przykładowa Klasa Abstrakcyjna

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

To będzie działać dobrze

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

Bar zwróci błąd

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

Songo zwróci błąd

class Songo extends Hello {

}
new Songo();

Klasa 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);
            }
        }
    }
}
 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/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-25 09:26:22

Może to być trochę "włamanie", ale wykonuje zadanie z bardzo małym wysiłkiem, ale po prostu z innym Komunikatem o błędzie, jeśli stała nie jest zadeklarowana w klasie potomnej.

Deklaracja stałej self-referential jest poprawna składniowo i parsuje bez problemu, tylko rzucając błąd, jeśli ta deklaracja jest rzeczywiście wykonywana w czasie wykonywania, Więc deklaracja SELF-referential w klasie abstrakcyjnej musi być nadpisana w klasie potomnej, w przeciwnym razie będzie błąd krytyczny: Cannot declare self-referencing constant.

W tym przykładzie, abstrakcyjna, nadrzędna klasa Foo zmusza wszystkie swoje dzieci do zadeklarowania zmiennej NAME. Ten kod działa poprawnie, wyprowadzając Donald. Jeśli jednak Klasa potomna Fooling nie zadeklarowała zmiennej , zostanie wywołany błąd krytyczny.

<?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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-31 07:26:59

Niestety nie... stała jest dokładnie tym, co jest napisane na puszce, stała. Raz zdefiniowany nie może być ponownie zdefiniowany, więc w ten sposób nie można wymagać jego definicji poprzez abstrakcyjne dziedziczenie lub Interfejsy PHP.

Jednak... możesz sprawdzić, czy stała jest zdefiniowana w konstruktorze klasy nadrzędnej. Jeśli nie, rzuć wyjątek.

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

To najlepszy sposób na zrobienie tego z twojego początkowego opisu.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-29 00:24:27

Nie, ale można spróbować innych sposobów, takich jak metody abstrakcyjne:

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
}  

Lub członkowie statyczni:

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
} 

Źródło

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-04 11:31:55