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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10368620/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 22:01:26  来源:igfitidea点击:

Abstract constants in PHP - Force a child class to define a constant

phpconstantsabstract

提问by Alex

I noticed that you can't have abstract constants in PHP.

我注意到在 PHP 中不能有抽象常量。

Is there a way I can force a child class to define a constant (which I need to use in one of the abstract class internal methods) ?

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

采纳答案by Baba

A constantis a constant; there is no abstractor privateconstants in PHP as far as I know, but you can have a work around:

Aconstantconstant; 据我所知,PHP 中没有abstract或没有private常量,但您可以解决以下问题:

Sample Abstract Class

示例抽象类

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

This would run fine

这会运行良好

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

Barwould return Error

酒吧会返回错误

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

Songowould return Error

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

回答by WebSmithery

This may be a bit of a ‘hack', but does the job with very little effort, but just with a different error message if the constant is not declared in the child class.

这可能有点“黑客”,但只需很少的努力即可完成这项工作,但如果未在子类中声明常量,则会显示不同的错误消息。

A self-referential constant declaration is syntactically correct and parses without problem, only throwing an error if that declaration is actually executed at runtime, so a self-referential declaration in the abstract class mustbe overridden in a child class else there will be fatal error: Cannot declare self-referencing constant.

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

In this example, the abstract, parent class Fooforces all its children to declare the variable NAME. This code runs fine, outputting Donald. However, if the child class Foolingdid notdeclare the variable, the fatal error would be triggered.

在此示例中,抽象的父类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;

回答by Jamie Rumbelow

Unfortunately not... a constant is exactly what it says on the tin, constant. Once defined it can't be redefined, so in that way, it is impossible to require its definition through PHP's abstract inheritance or interfaces.

不幸的是,不是......一个常数正是它在锡上所说的,常数。一旦定义了就不能重新定义,这样就不可能通过 PHP 的抽象继承或接口来要求它的定义。

However... you could check to see if the constant is defined in the parent class's constructor. If it doesn't, throw an 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();

This is the best way I can think of doing this from your initial description.

这是我从你最初的描述中想到的最好的方法。

回答by Songo

No, yet you could try other ways such as abstract methods:

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

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
}  

or static members:

或静态成员:

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

来源

回答by Code Spirit

Tested in php 7.2 but should since 5.3 you can leverage late static binding to archive this behaviour. It will throw an Fatal Error achchieving the same as an Exception because in most causes you dont want to handle FatalErrors at runtime. If you want so you can easily implement a custom error handler.

在 php 7.2 中测试过,但从 5.3 开始,您应该可以利用后期静态绑定来存档此行为。它会抛出与异常相同的致命错误,因为在大多数情况下,您不想在运行时处理致命错误。如果您愿意,您可以轻松实现自定义错误处理程序。

So the following works for me:

所以以下对我有用:

<?php

abstract class Foo {

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

}


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

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

If you remove the constyou will get an:

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

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

回答by Adam Berry

PHP Interfaces support constants. It's not as ideal because you would have to remember to implement the interface on every child class so it kind of defeats the purpose partially.

PHP 接口支持常量。它并不理想,因为您必须记住在每个子类上实现接口,因此它部分地违背了目的。