Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP中的抽象常量-强制子类定义常量_Php_Constants_Abstract - Fatal编程技术网

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

PHP中的抽象常量-强制子类定义常量,php,constants,abstract,Php,Constants,Abstract,我注意到在PHP中不能有抽象常量 有没有一种方法可以强制子类定义一个常量(我需要在抽象类内部方法中使用它)?a常量是一个常量;据我所知,PHP中没有abstract或private常量,但您可以解决以下问题: 示例抽象类 abstract class Hello { const CONSTANT_1 = 'abstract'; // Make Abstract const CONSTANT_2 = 'abstract'; // Make Abstract const CO

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


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

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

示例抽象类

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();
这将运行良好

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();
class Songo extends Hello {

}
new Songo();
Songo将返回错误

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

}
new Songo();
执行者类

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

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

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
} 

不幸的是,没有。。。一个常数就是它在锡罐上写的,常数。一旦定义了它,就不能重新定义,因此,通过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();

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

这可能有点“黑客”,但做这项工作几乎不费吹灰之力,但如果未在子类中声明常量,则只会显示一条不同的错误消息

自引用常量声明在语法上是正确的,解析时不会出现问题,只有在运行时实际执行该声明时才会抛出错误,因此抽象类中的自引用声明必须在子类中重写,否则将出现致命错误:
无法声明自引用常量

在本例中,抽象的父类
Foo
强制其所有子类声明变量
NAME
。此代码运行良好,输出
Donald
。但是,如果子类
愚弄
没有声明变量,则会触发致命错误

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

在PHP7.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


PHP接口支持常量。这不是很理想,因为您必须记住在每个子类上实现接口,所以它在某种程度上违背了目的。

这不是一个常量,这是一个函数。@Baba good work around:)但这是否意味着对于每个常量都会有一个if语句?@Songo。。您可以看到更新的代码。。它已经在为正常和抽象工作了。。。。我更改了关键字,以便您能够理解。虽然这样做有效,但我觉得此解决方案相当繁琐、不可靠,并且引入了不必要的复杂性。如果抽象类依赖于运行时信息,@Alex应该将模板方法模式与常量方法一起使用,或者检查处理方法内部是否存在默认常量值。此外,在ctor中对强制执行器的硬编码依赖很容易被忽略。一个子类可以覆盖ctor,然后所有那些对反射API的肮脏摆弄就不再有效了。另外,如果您知道您的解决方案只是概念证明,不用于生产,那么答案应该是这样的。来到SO的人通常会为他们在生产中遇到的实际问题寻求帮助。但他们不一定知道什么是不好的做法、黑客行为或只是为了“教育目的”。除非你告诉我。这就是为什么我要指出它。一个常量一旦在每一个类、函数方法或其他方面都设置了它的可用性,它就具有了完整的作用域。这没有意义,请提供一些代码来解释abit。要么在抽象类中定义一个常量(因此每个子类都有一个常量,即使它没有定义自己的常量),要么使用抽象函数(强制每个子类定义自己的常量)。编辑:您的问题的简短答案是“否”。如果必须在运行时设置一个值,则根据定义,它是一个变量。如果您从web上的其他位置复制代码,请确保您也引用了源代码。以上代码取自“这比公认的答案更好”。如果抽象类依赖于子类,请定义一个抽象方法来声明此依赖关系,并使用该方法从实现类获取值。可以在子类中重写常量的值。常数不受这种重新定义的影响。@Brillian,是的,那不是常数。@AlfonsoFernandez-Ocampo如果它在不同的上下文中(即子类),那么它实际上是一个不同的常数,而不是对第一个常数的更改。拥有“常数”意味着没有任何东西可以在其他地方定义来掩盖常数,这将是非常极端的。在我看来,这是最优雅的解决方案——谢谢!仅供参考,我刚刚在PHP7.2中尝试过这个,但它不起作用。抛出异常:致命错误:未捕获错误:无法声明自引用常量“self::RAW\u DATA\u CACHE\u KEY”,我刚刚用PHP7.2.19进行了测试,效果非常好。请注意,您不能在类内调用self::NAME,但要调用$this::NAME。@ChrisFlannagan try
static::NAME
PhpStorm 2019.3.4将其错误标记为“无法声明自引用常量”,但这是一个错误,这是有效的语法。投票支持错误报告:不幸的是,你没有得到编译时错误——你只在执行
echo static::BAR时得到错误。IDE或静态分析器不会告诉类Bar的作者他们必须定义常量。