【问题标题】:Why doesn't PHP permit private constants? [duplicate]为什么 PHP 不允许私有常量? [复制]
【发布时间】:2015-03-01 17:00:18
【问题描述】:

为什么 PHP 不允许私有常量?

我知道有一些变通方法,例如改用私有静态属性。

但是,从 OOP 或软件设计的角度来看,原因是什么?

【问题讨论】:

  • 很难说为什么。希望其中一位 PHP 开发人员能过来。我想,类常量只存在于 PHP 5.3 之后,所以也许它还没有实现。我的猜测是,它不是一个非常有用的功能,因此在愿望清单上的位置很低。保护方法和属性比保护常量更有用。
  • @AlexanderO'Mara 这没有任何意义。我想防止人们依赖我的私有常量,以便以后可以轻松更改它们而不会激怒用户。
  • @halfer:这些问题还有很多——但这个问题是出于我认为不同的原因。
  • 我不明白为什么这被标记为重复......这个问题不是问是否有 priv consts,而是为什么,在 2 个链接问题中从未回答过的部分。

标签: php constants private


【解决方案1】:

tl;tr

不实现私有常量的原因是什么?

这是个好问题。

他们真的考虑过这个吗?

我不知道。

  • 在搜索 PHP 内部邮件列表时,我没有发现任何关于此主题的信息。 除非内部成员大声疾呼,否则我们永远不会知道。

    关于语言的历史 - 有点 1:1 C 方法包装,一些来自 Perl (regexp),一些来自 Java (oop) - 这个想法可能会在寻找新的语言特性时突然出现.

    我会将“私有常量”的概念与 VisualBasic 或 Java 联系起来。我怀疑 VB 对 PHP 有很大或任何影响。 VB 允许在“模块”中定义“私有常量”——这是默认的访问范围。 Visual Basic 不允许在接口和命名空间中使用常量(但 PHP 允许)。

    PHP 可能包含一些来自 Java 的 OOP 概念,但有一个很大的区别:常量是 Java 中的变量。它们的访问修饰符/可见性级别是:“public、private、final 和 static”。私有常量声明如下所示:"private static final String MYCONST = "My Constant"; 这是 OOP - 故事结束。与此相比,PHP 常量访问感觉更骇人听闻 - 但它更简单,而且您仍然可以使用解决方法。

  • PHP manual for Class Constants中的第一条评论是:

    这似乎很明显,但类常量始终是公开可见的。 它们不能被设为私有或受保护。我没有看到它声明 在任何地方的文档中。

    为什么这很明显? “为什么类常量默认是公共的而不是私有的?” 也许,这是缺少的语言功能,因为并非所有班级成员都可以正确隐藏。 他是对的,当你从 Java 或 VB 转向 PHP 时,就会出现这个问题。

  • 我们来看看PHP spec。 PHP 的当前实现状态是:类常量始终是公共的和静态的。因此,一次又一次地为 Facebook 编写如此详细的文档点赞:作者考虑了不同的可见性或访问控制级别。

我们来看看接口、类、常量和可见性:

  • “const”这个概念与“private static”有什么不同?

    静态变量可以改变,常量不能改变。 您不能将函数的运行时值分配给 const (const A = sprintf('foo %s', 'bar');),而是分配给私有静态变量。

  • 接口可能有常量 - 它们不能被覆盖。

  • 一个类可能有一个常量 - 它可能被继承的类/接口覆盖。

  • 还有一种称为“常量接口模式”的 OOP 模式 - 它描述了仅使用接口来定义常量,并让类实现该接口以方便地对这些常量进行语法访问。

    提供了一个接口,以便您可以描述一组函数,然后将函数的最终实现隐藏在实现类中。这使您可以更改功能的实现,而无需更改使用方式。存在接口以公开 API。

    通过在接口中定义常量并通过类实现接口,常量成为 API 的一部分。实际上,您正在将实现细节泄漏到 API 中。这就是为什么有些人认为这是一种反模式,其中包括 Joshua Bloch (Java)。

现在,让我们尝试结合一些概念,看看它们是否合适。

假设我们试图避免来自上面的批评,那么你需要引入一种语法,它允许对常量进行合格的访问,但在 API 中隐藏了常量。您可以通过可见性级别提出“访问控制”:“公共、私人、受保护、朋友、敌人”。目标是防止包或类的用户依赖于该包或类实现的不必要细节。一切都是为了隐藏实现细节,对吧?

“接口”中的“私有常量”呢?

这实际上可以解决来自上面的批评,对吗? 但是接口与“私有”的结合是没有意义的。概念是相反的。 这就是为什么界面不允许“私人”访问/可见性级别。 “接口”中的“私有”常量也将是互斥的。

“类”中的“私有常量”呢?

    class a { 
        /*private*/ const k = 'Class private constant k from a'; 
    }

    class b extends a
    {
        const k = 'Overridden private constant a::k with Class constant k from b';

        const k_a = parent::k; 

        // fatal error: self-referencing constant
        #const k_selfref = self::k . ' + ' . self::k_selfref; 

        // fatal error: "static::" is not allowed in compile-time constants
        #const k_staticref = static::k; 
    }

    // direct static access would no longer work, if private 
    // you need an instance of the parent class or an inheriting class instance
    echo a::k; 
    echo b::k;  
    echo b::k_a;

    $obj_b = new b;
    echo $obj_b::k;
    echo $obj_b::k_a;

有什么好处吗?

  • 类中的私有常量不会在 API 中公开。这是很好的 OOP。

  • 从外部对父常量的访问将是类和/或继承访问。

    echo a::k,现在可以使用 - 可能会以“致命错误:尝试访问没有类实例或继承的私有常量。”。

  • (如果没有为 const 分配运行时值,这可能仍然仅在编译时工作。但我不确定这个。)

有什么注意事项吗?

  • 我们将失去对常量的直接静态访问。

  • 要求创建一个类的实例,只是为了访问常量,是一种资源浪费。直接静态访问节省资源,简单。如果我们引入私有,那将丢失并且访问将被绑定到实例。

  • “私有常量”隐含地是“私有静态常量”。访问运算符仍然是“::”。

    一个可能的后续变化是切换到隐式非静态常量。 那是公元前的休息时间。 如果将默认行为切换为非静态,访问运算符将从“::”更改为“->”。 这建立了对常量的适当OOP对象访问,这与Java的“常量作为具有访问级别的变量”的概念相媲美。这有点像这样:http://3v4l.org/UgEEm。当常量声明为“public static const”时,访问运算符变为静态,对吗?

收益是否足以实现它?

我不知道。有待商榷。 我喜欢这两个:const 静态访问,因为它非常简单,而且“常量作为变量”的概念和适当的访问级别。

实现之后,为了节省资源和保持快速,大家开始(重新)声明“public static const”,放弃实例要求,违反OOP;)

顺便说一句:我在试验这个答案的代码时发现了一个 HHVM 溢出。

【讨论】:

    【解决方案2】:

    为什么 PHP 不允许私有常量?

    在 PHP 中,常量是 接口 的一部分,并且接口始终是公共的(这就是接口的用途)。

    另见PHP Interfaces

    我很确定这就是设计方面的原因。

    关于您的问题下有人想要降低常量的可见性以稍后更改它们的评论,我想说这听起来更像是一个变量,而不是一个不会改变其值的常量。它是恒定的。

    【讨论】:

      猜你喜欢
      • 2011-10-09
      • 1970-01-01
      • 2014-11-03
      • 1970-01-01
      • 2019-03-02
      • 1970-01-01
      • 1970-01-01
      • 2014-03-01
      • 2020-11-22
      相关资源
      最近更新 更多