PHP 特征 - 定义通用常量

Posted

技术标签:

【中文标题】PHP 特征 - 定义通用常量【英文标题】:PHP traits - defining generic constants 【发布时间】:2014-08-13 00:35:31 【问题描述】:

定义可以被命名空间中的多个类使用的常量的最佳方法是什么?我试图避免过多的继承,所以扩展基类不是一个理想的解决方案,我正在努力寻找一个使用特征的好的解决方案。这在 php 5.4 中是否有可能,还是应该采取不同的方法?

我有以下情况:

trait Base

    // Generic functions


class A 

    use Base;


class B 

    use Base;

问题是无法在 PHP 特征中定义常量。理想情况下,我想要以下内容:

trait Base

    const SOME_CONST = 'someconst';
    const SOME_OTHER_CONST = 'someotherconst';

    // Generic functions

然后可以通过应用 trait 的类访问这些:

echo A::SOME_CONST;
echo B::SOME_OTHER_CONST;

但是由于特征的限制,这是不可能的。有什么想法吗?

【问题讨论】:

可以使用静态属性,它不是一个常量,但在调用它时也只有一个字符不同...public static $SOME_VAR = 'someconst';echo B::$SOME_VAR 感谢您的提示。这是一种选择,尽管这是一项重构工作,而不是新代码,所以我更希望行为保持不变而不是更新所有常量调用(有很多)。 你可以使用接口来声明常量。 bugs.php.net/bug.php?id=70986 bugs.php.net/bug.php?id=70986 现在已被bugs.php.net/bug.php?id=75060 取代 【参考方案1】:

我最终使用了user sectus's suggestion 的接口,因为这感觉是处理这个问题的最少问题的方式。使用接口来存储常量而不是 API 契约有一种不好的味道,所以这个问题可能更多是关于 OO 设计而不是 trait 实现。

interface Definition

    const SOME_CONST = 'someconst';
    const SOME_OTHER_CONST = 'someotherconst';


trait Base

    // Generic functions


class A implements Definition

    use Base;


class B implements Definition

    use Base;

这允许:

A::SOME_CONST;
B::SOME_CONST;

【讨论】:

所以接口可以有常量...但特征不能? PHP 变得越来越奇怪了。 @Adambean 覆盖一个常量违背了constant 的目的,它并不意味着改变。 然而,如果我想在 trait 的代码实现中使用一个值,这是不可能的。 @Aknosis 我个人认为它不仅仅是一个常数在其生命周期内不会改变价值。这并不意味着在扩展类时不能用另一个值重新定义它(并使用 [例如] static::VALIDATION_REGEX 来获取 late-static-bound 值) PHP '错误'#75060【参考方案2】:

您也可以使用静态变量。它们可以在类或特征本身中使用。 - 作为 const 的替代品,对我来说效果很好。

trait myTrait 
    static $someVarA = "my specific content";
    static $someVarB = "my second specific content";


class myCustomClass 
    use myTrait;

    public function hello()
    
        return self::$someVarA;
    

【讨论】:

我知道这是旧的,但你不想用 const 来改变值吗? 你不能在 Trait 中使用常量。【参考方案3】:

要限制常量的范围,您可以在命名空间中定义它们:

namespace Test;

const Foo = 123;

// generic functions or classes

echo Foo;
echo namespace\Foo;

这种方法的一个缺点是自动加载对常量不起作用,至少对 5.4 不起作用;解决这个问题的典型方法是将这些常量包装在一个静态类中,即:

namespace Test;

class Bar

    const Foo = 123;

【讨论】:

有趣的想法。我没有意识到您可以直接访问命名空间常量。问题是这个库是 PSR-0 自动加载的,所以我担心这种方法行不通。不过感谢您的回答。 @orciny 好吧,如果将这些常量包装在静态类中,自动加载将起作用;不是最漂亮的代码的最闪亮的例子,但它会工作:)【参考方案4】:

不是很好,但也许...

trait Base

    public static function SOME_CONST()
    
        return 'value1';
    

    public static function SOME_OTHER_CONST()
    
        return 'value2';
    

    // generic functions


class A

    use Base;


class B

    use Base;


echo A::SOME_CONST();
echo B::SOME_OTHER_CONST();

【讨论】:

请注意那些没有遵循的人,这些是静态方法,而不是常量。虽然使用时它们看起来有点像常量。如果您要这样做并且希望这些方法的行为更像常量,则需要在方法前加上关键字 final 以确保它们不会被覆盖(与常量相同的行为)。 @John Hunt, final 不适用于特质,请参阅 ***.com/a/33481511/251735【参考方案5】:

从 PHP 8.1 开始,可以在特征中使用 readonly 属性。

<?php
trait A

    public readonly int $variable;
    
    protected function initA(int $newValue)
        $this->variable = $newValue;
    

    public function changeVariable(int $newValue)
        $this->variable = $newValue;
    


class B 
    use A;

    public function __construct() 
        $this->initA(1);
    


$b = new B();
$b->changeVariable(5); // should faild: Fatal error: Uncaught Error: Cannot modify readonly property B::$variable

【讨论】:

【参考方案6】:

另外需要考虑的是你是否可以使用抽象类来代替,然后继承。

abstract class Base

    const A = 1;
    const B = 2;


class Class1 extends Base 
class Class2 extends Base 

echo Class1::A;
echo Class2::B;

当然,trait 的部分原因是用组合替换复杂的继承树。视情况而定。

【讨论】:

以上是关于PHP 特征 - 定义通用常量的主要内容,如果未能解决你的问题,请参考以下文章

通用特征矩阵/向量对象传输到自定义矩阵/向量容器

无法在锈柴油中使用通用参数实现特征

OpenHarmony eTS通用日志组件,写日志快一点

具有通用特征的结构,这也是通用特征

通用自定义PHP日期格式

通用参考和常量