问题描述
为什么PHP不允许私有常量?
我知道有些解决方法,例如改为使用私有静态属性。
但是,从OOP或软件设计的角度来看,这是什么原因?
tl; tr
不实施私有常量的原因是什么?
这是一个好问题。
他们真的考虑过吗?
我不知道。
-
在PHP内部邮件列表中进行搜索时,我没有找到与该主题有关的任何内容。
除非内部成员大声疾呼,否则我们永远不会知道。
关于语言的历史-1:1 C方法换行,Perl(regexp),Java(oop)-有可能
我将私有常量的概念与VisualBasic或Java相关联。我怀疑VB是否会对PHP产生重大影响。 VB允许在模块中定义私有常量-这是默认的访问范围。 Visual Basic不允许接口和命名空间中的常量(但PHP允许)。
PHP可能包含Java的一些OOP概念,但有一个很大的区别:常量是Java中的变量。它们的访问修饰符/可见性级别为:公共,私有,最终和静态。一个私有常量声明看起来像这样:
private static final String MYCONST = My Constant;
这是OOP-故事的结尾。与之相比,PHP常量访问感觉更加骇俗- -
是:
为什么这么明显?为什么默认情况下,一个类常量是公共的而不是私有的?
也许这是一种缺少的语言功能,因为不是全部类成员可以正确隐藏。
是的,当您从Java或VB到PHP时,会弹出此问题。 -
让我们来看一眼f = https://github.com/php/php-langspec/blob/master/tests/constants/constants.php#L165 rel = nofollow> PHP规范。 PHP中当前的实现状态是:类常量始终是公共的和静态的。因此,一次又一次地,Facebook赞成编写这样的详细文档:作者考虑了不同的可见性或访问控制级别。
让我们看一下界面,类,常量和可见性:
-
如何
静态变量可以更改,常量不能更改。
静态变量可以更改,常量不能更改。
您不能将函数的运行时值分配给const(const A = sprintf('foo%s','bar');
),但是 -
接口可能具有常量-无法覆盖它们。
-
一个类可能有一个常量-可能被继承的类/接口覆盖。
-
还有一个称为常量接口模式的OOP模式。 -它描述了仅使用接口来定义常量,并使用类实现该接口以便对这些常量进行方便的语法访问。
您可以描述一组功能,然后将这些功能的最终实现隐藏在实现类中。这使您可以更改功能的实现,而无需更改其使用方式。存在用于公开API的接口。
通过在接口中定义常量并由类实现接口,这些常量将成为API的一部分。实际上,您正在将实现细节泄漏到API中。这就是为什么有些人(例如Joshua Bloch(Java))认为这是一种反模式。
现在,让我们尝试结合一些概念,看看它们是否合适。
让我们假装我们试图避免上面的批评,然后您需要引入一种语法,该语法允许对常量进行合格访问,但在API中隐藏了该常量。您可以通过可见性级别提出访问控制:公共,私有,受保护,朋友,敌人。目的是防止程序包或类的用户依赖于该程序包或类的实现的不必要的细节。全部就是隐藏实现细节,对吗?
接口中的私有常量如何?
从上面解决批评,对不对?
但是将界面与私人结合使用是没有意义的。这些概念是相反的。
这就是为什么界面不允许私有访问/可见性级别的原因。
而且接口中的私有常量也将互斥。
类中的私有常量呢? ?
A类{
/ * private * / const k ='来自一种';
}
类b扩展了一个
{
const k =‘覆盖私有常量a :: k,其中类常量k来自b’;
const k_a = parent :: k;
//致命错误:自引用常量
#const k_selfref = self :: k。 ’+’。自我:: k_selfref;
//致命错误:编译时常量不允许使用 static ::
#const k_staticref = static :: k;
}
//直接静态访问将不再起作用,如果私有
//您需要父类的实例或继承类的实例
echo a :: k;
echo b :: k;
echo b :: k_a;
$ obj_b =新b;
echo $ obj_b :: k;
echo $ obj_b :: k_a;
有好处吗?
-
该类中的私有常量不会在API中公开。这是一个很好的OOP。
-
从外部访问父常量将是类和/或继承访问。
echo a :: k
现在可以正常工作-可能会显示致命错误:尝试在没有类实例或继承的情况下访问私有常量。 -
(如果没有将运行时值分配给const,这可能仍仅在编译时有效。但是我不确定
有警告吗?
-
我们将失去对常量的直接静态访问。
-
需要一个a的实例创建类,仅仅访问常量,是浪费资源。直接静态访问可以节省资源并且非常简单。如果我们引入了private,则将丢失该访问,并且访问将绑定到实例。
-
private const隐式是 private static const。访问运算符仍然是 ::。
可能的后续更改是切换到隐式非静态常量。
这是BC休息时间。
如果将默认行为切换为非静态,则访问运算符将从 ::更改为->。
这将建立对常量的适当的OOP对象访问,这类似于Java的常量作为具有访问级别的变量的概念。可以这样工作:。当常量声明为 public static const时,访问运算符将变为static,对吗?
好处是否足以实施?
我不知道。有待讨论。
我都喜欢:const静态访问,因为它非常简单,而且常量作为变量的概念以及适当的访问级别。
在实现之后,为了节省资源并保持快速发展,每个人都开始(重新)声明 public static const,以放弃实例要求并违反OOP;)
顺便说一句:我在尝试此答案的代码时发现HHVM溢出。
Why doesn't PHP permit private constants?
I am aware that there are workarounds, such as using a private static property instead.
However, from an OOP or software design perspective, what was the reasoning?
tl;tr
What was the reasoning to not implement private constants?
This is a good question.
Did they really consider this?
I don't know.
When searching through the PHP internals mailing list, i found nothing about this topic.Unless a internal's member speaks up, we'll never know.
With regard to the history of the language - a bit 1:1 C method wrapping, some bits from Perl (regexp), some bits Java (oop) - it's possible that this idea popped up, while looking for new language features.
I would relate the concept of a "private constant" to VisualBasic or Java. I doubt that VB has a big or any influence on PHP. VB allows the definition of "private constants" in "Modules" - it's the default access scope. Visual Basic doesn't allow constants in Interfaces and Namespaces (but PHP does).
PHP might include some OOP concepts from Java, but there is one big difference: constants are variables in Java. Their access modifiers / visibility levels are: "public, private, final and static". A private constant declaration looks like this:
"private static final String MYCONST = "My Constant";
It's OOP - end of story. PHP constant access feels more hackish compared to that - BUT it's more simple and you still have the workaround at hand.The first comment in the PHP manual for Class Constants is:
Why is this obvious? "Why is a class constant public by default and not private?"Maybe, it's a missing language feature, because not all class members can be hidden properly.And he is right, when you come from Java or VB to PHP this question pops up.
Let's take a look at the PHP spec. The current state of implementation in PHP is: class constants are always public and static. So, again and again, thumbs up for Facebook for writing such detailed document: the author considered different visibility or access-control levels.
Let's take a look at interface, class, constant and visibility:
How does the concept "const" differ from "private static"?
The static variable can be changed, the constant cannot be changed.You cannot assign the runtime value of a function to a const (
const A = sprintf('foo %s', 'bar');
), but to a private static var.An interface might have constants - they cannot be overridden.
A class might have a constant - which might be overridden by a inheriting class/interface.
There is also an OOP pattern called "constant interface pattern" - it describes the use of an interface solely to define constants, and having classes implement that interface in order to achieve convenient syntactic access to those constants.
An interface is provided so you can describe a set of functions and then hide the final implementation of the functions in an implementing class. This allows you to change the implementation of the functions, without changing how you use it. Interfaces exist to expose an API.
And by defining constants in an interface and implementing the interface by a class, the constants become part of the API. In fact, you are leaking implementations details into the API. That's why some consider this being an anti-pattern, among them Joshua Bloch (Java).
Now, let's try to combine some concepts and see if they fit.
Let's pretend we try to avoid the critique from above, then you need to introduce a syntax, which allows qualified access to the constant, but hides the constant in the API. You could come up with "Access control" via visibility levels: "public, private, protected, friend, foe". The goal is to prevent the users of a package or class from depending on unnecessary details of the implementation of that package or class. It is all about hiding implementation details, right?
What about "private constants" in "interfaces"?
That would actually solve the critique from above, right?But the combination of interface with "private", doesn't make sense. The concepts are contrary.That's why interface do not allow "private" access/visibility-levels.And a "private" constant in an "interface" would be mutually exclusive, too.
What about "private constants" in "classes"?
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;
Is there a benefit?
The private constant in the class wouldn't be exposed in the API. This is good OOP.
The access to the parent constant from outside would be a class and/or inheritance access.
echo a::k
, which now works - could respond with "Fatal error: Trying to access a private constant without a class instance or inheritance.".(This might still work solely at compile-time, if there is no run-time value assignment to a const. But i'm not sure about this one.)
Are there caveats?
We would lose direct static access to constants.
Requiring that an instance of a class is created, just to access constants, is a waste of resources. Direct static access saves resources and is simple. If we introduce private, that's lost and the access would be bound to the instance.
A "private const" is implicitly a "private static const". The access operator is still "::".
A possible follow-up change would be the switch to implicitly non-static constants.That's a BC break.If you switch the default behavior to non-static, the access operator changes from "::" to "->".This establishes a proper OOP object access to constants, which is comparable to Java's concept of "constants as variables with access level". This would work a bit like this: http://3v4l.org/UgEEm. The access operator changes to static, when the constant is declared as "public static const", right?
Is the benefit good enough to implement it?
I don't know. It's up for discussion.I like both: the const static access, because it's dead simple and the concept of "constants as variables" and proper access levels.
After that's implemented, in order to save resources and keep going fast, everyone starts to (re-)declare "public static const", to drop the instance requirement and violate OOP ;)
And btw: i found an HHVM overflow, while experimenting with code of this answer.
这篇关于PHP为什么不允许私有常量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!