PHP中的抽象常量 - 强制子类定义常量

时间:2012-04-29 00:05:00

标签: php constants abstract

我注意到你不能在PHP中使用抽象常量。

有没有办法可以强制子类定义一个常量(我需要在其中一个抽象类内部方法中使用)?

6 个答案:

答案 0 :(得分:30)

这可能有点像'hack',但只需很少的努力就可以完成工作,但如果未在子类中声明常量,则只需使用不同的错误消息。

自引用常量声明在语法上是正确的并且解析没有问题,只有在运行时实际执行该声明时才会抛出错误,因此抽象类中的自引用声明必须被覆盖在子类中,会出现致命错误:Cannot declare self-referencing constant

在此示例中,抽象父类Foo强制其所有子级声明变量NAME。此代码运行正常,输出Donald。但是,如果子类Fooling 声明变量,则会触发致命错误。

<?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;

答案 1 :(得分:27)

constantconstant;据我所知,PHP中没有abstractprivate常量,但你可以解决这个问题:

抽象类示例

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

这样运行正常

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

会返回错误

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

Songo 会返回错误

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

答案 2 :(得分:16)

不幸的是,不是......一个常数就像它在锡上说的一样,不变。一旦定义就无法重新定义,因此以这种方式,不可能通过PHP的抽象继承或接口来定义它的定义。

但是......您可以检查是否在父类的构造函数中定义了常量。如果没有,则抛出异常。

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

这是我从最初的描述中想到的最佳方式。

答案 3 :(得分:7)

不,你可以尝试其他方法,例如抽象方法:

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
}  

或静态成员:

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
} 

Source

答案 4 :(得分:1)

在php 7.2中进行了测试,但是从5.3开始,您可以利用后期静态绑定来存档此行为。它会引发致命错误,并与异常一样,因为在大多数情况下,您都不希望在运行时处理致命错误。 如果需要,可以轻松实现自定义错误处理程序。

所以以下对我有用:

<?php

abstract class Foo {

    public function __construct() {
        echo static::BAR;
    }

}


class Bar extends Foo {
    const BAR = "foo bar";
}

$bar = new Bar();    //foo bar

如果您删除const,您将获得:

Fatal error: Uncaught Error: Undefined class constant 'BAR' in ...

答案 5 :(得分:-1)

PHP接口支持常量。它不是那么理想,因为您必须记住要在每个子类上实现该接口,这样才能部分地达到目的。