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

时间:2015-01-03 17:54:50

标签: php constants private

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

我知道有一些解决方法,例如使用私有静态属性。

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

2 个答案:

答案 0 :(得分:1)

  

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

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

另见PHP Interfaces

我很确定这是设计明智的原因。

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

答案 1 :(得分:1)

<强> TL; TR

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

这是一个很好的问题。

他们真的考虑过这个吗?

我不知道。

  • 在PHP内部邮件列表中搜索时,我没有发现这个主题。 除非内部成员说出来,否则我们永远不会知道。

    关于语言的历史 - 比特1:1 C方法换行,来自Perl(regexp)的一些比特,一些比特Java(oop) - 这个想法可能会弹出,同时看起来用于新的语言功能。

    我会将&#34;私人常数&#34;的概念联系起来。到VisualBasic或Java。我怀疑VB对PHP有很大影响或任何影响。 VB允许定义&#34;私有常量&#34; in&#34; Modules&#34; - 它是默认的访问范围。 Visual Basic不允许在接口和命名空间中使用常量(但PHP确实如此)。

    PHP可能包含一些来自Java的OOP概念,但有一个很大的区别:常量是Java中的变量。他们的访问修饰符/可见性级别为:&#34; public,private,final和static&#34;。私有常量声明如下所示:"private static final String MYCONST = "My Constant";它的OOP - 故事结束。与此相比,PHP持续访问感觉更加苛刻 - 但它更简单,您仍然可以使用手头的解决方法。

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

      

    看起来很明显,但是类常量总是公开可见的。   它们不能被私有或受到保护。我不认为这说明了   在任何地方的文档中。

    为什么这很明显? &#34;为什么一个类默认是公共的而不是私有的?&#34; 也许,它是一种缺失的语言功能,因为不是所有的班级成员都可以被正确隐藏。 他是对的,当你从Java或VB到PHP时,这个问题就出现了。

  • 让我们来看看PHP spec。 PHP中当前的实现状态是:类常量总是公共的和静态的。所以,一次又一次地为Facebook撰写这样详细的文档竖起大拇指:作者考虑了不同的可见性或访问控制级别。

让我们来看看界面,类,常量和可见性:

  • 概念&#34; const&#34;不同于&#34;私人静态&#34;?

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

  • 接口可能有常量 - 无法覆盖它们。

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

  • 还有一个名为&#34;常量接口模式的OOP模式&#34; - 它描述了仅用于定义常量的接口的使用,并且让类实现该接口以便实现对这些常量的方便的语法访问。

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

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

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

让我们假装我们试图避免上面的批评,然后你需要引入一种语法,允许对常量进行限定访问,但隐藏API中的常量。您可以提出&#34;访问控制&#34;通过能见度水平:&#34;公共,私人,受保护,朋友,敌人&#34;。目标是防止包或类的用户依赖于该包或类的实现的不必要细节。这一切都是关于隐藏实现细节,对吗?

&#34;私人常数&#34;在&#34;接口&#34;?

这实际上可以解决上面的批评,对吧? 但是界面与&#34;私人&#34;的组合并没有意义。这些概念是相反的。 这就是为什么界面不允许&#34;私人&#34;访问/能见度的水平。 一个&#34;私人&#34;恒定在&#34;界面&#34;也是互相排斥的。

&#34;私人常数&#34;在&#34;班级&#34;?

    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,现在有效 - 可以回复&#34;致命错误:尝试访问没有类实例或继承的私有常量。&#34;。

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

有警告吗?

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

  • 要求创建类的实例,只是为了访问常量,这是浪费资源。直接静态访问可以节省资源并且很简单。如果我们引入私有,则会丢失并且访问权限将绑定到实例。

  • A&#34;私人const&#34;隐式地是一个&#34;私有静态const&#34;。访问操作符仍然是&#34; ::&#34;。

    可能的后续更改是切换到隐式非静态常量。 这是BC的休息时间。 如果将默认行为切换为非静态行为,则访问运算符将从&#34; ::&#34;到&#34; - &gt;&#34;。 这建立了对常量的正确OOP对象访问,这与Java的#34;常量概念相似,作为具有访问级别&#34;的变量。这有点像这样:http://3v4l.org/UgEEm。当常量声明为&#34; public static const&#34;时,访问操作符更改为static;对吗?

这个好处是否足以实现它?

我不知道。它需要讨论。 我喜欢两者:const静态访问,因为它很简单,并且#34; constants的概念作为变量&#34;和适当的访问级别。

在实施之后,为了节省资源并保持快速进入,每个人都开始(重新)声明&#34; public static const&#34;,删除实例要求并违反OOP;)

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