Why doesn't PHP permit private constants? [duplicate] - php

This question already has answers here:
Are private constants possible in PHP? [duplicate]
(4 answers)
Why doesn't PHP permit private const?
(2 answers)
Closed 8 years ago.
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:
It may seem obvious, but class constants are always publicly visible.
They cannot be made private or protected. I do not see it state that
in the docs anywhere.
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.

Why doesn't PHP permit private constants?
In PHP constants are part of the interface and the interface is public, always (that's what an interface is for).
See as well PHP Interfaces.
I'm pretty sure this is the reason design-wise.
Regarding the comment under your question that someone wants to reduce the visibility of constants to change them later, I'd say this sounds more like a variable than a constant which does not change it's value. It's constant.

Related

What's the visibility of a class by default in PHP?

I could find the default visibility of a property and a method in the PHP manual. But i couldn't find any info regarding the class itself.
My guess is that it's public. But if someone could link to the part where this is written in the manual i would appreciate it.
Simply Put
Public. PHP doesn't support anything other than public classes.
Unlike Java/.NET/etc, there isn't any concept of packages, assemblies, internal or nested classes. Namespaces are essentially just syntactic sugar to avoid IncrediblyLongClassNames, and can't provide any actual changes to visibility.
The entire idea makes much less sense in a non-compiled language, since regardless of what scope you use, anyone could still just take your class and declare it in public.
A PHP 7 Proviso: Anonymous Classes
PHP 7 introduced the concept of anonymous classes*, allowing on-the-fly class definitions. As a very basic example:
<?php
$foo = new class {
public function hello($what)
{
echo 'Hello ', $what, PHP_EOL;
}
};
(new $foo)->hello('world');
# Hello world
Because these can be assigned to variables, they can be limited to the scope of that variable, and passed around like any other.
Unlike most language that allow anonymous classes, in PHP they do not inherit anything from the scope in which they are defined. The linked documentation has some examples of how to work around this, by defining the anonymous class as inheriting from a parent or passing in constructor arguments.
*Strictly speaking, under the hood they do have names, and as such if someone can run get_class() on an instance then they can then instantiate their own copy, since they aren't garbage collected.
PHP are always public "by default", but the most accurate answer here is that PHP classes don't have such concept anyway.

Why do these lines of code execute successfully

I'm very familiar with OOP in C++ and Java and I'm new to it in PHP, afterall PHP claims to support OOP. I'm refactoring some codes given to me in my internship and I came across the following style of coding, in PHP.
<?php
class A {
public function echoVar(){
$this->__();
echo $this->var;
}
}
class B extends A{
function __(){
$this->var = 1;
}
}
$v = new B();
$v->echoVar();
Following my experience with C++ and especially Java, this wouldn't even try to compile, but the execution is fine in PHP. I understand that all languages aren't the same but why does PHP support this style. Is this style good or bad practices? how is this OOP?
With my knowledge, the following are what I think is wrong with this code.
var is not a defined attribute of the class B, and yet was accessed and given a value.
How/Why did super class A have access to method __ of subclass B without casting or abstraction.
I would ask how class A got access to the attribute var but the attribute itself was created out of magic. On a serious note, why did it have access to var.
I'm a OOP newbie in PHP, so please help me clarify these things.
This is an example of, uhm, not so great coding. First, I would suggest activating strict error reporting (E_ALL | E_STRICT | E_NOTICE).
If an class/object property which hasn't been declared before, is assigned a value, it is going to be created as public property of the object. However, with strict error reporting, you'd get thrown an E_NOTICE.
Although the __ belongs to the B class, it can be called from A, when B is instantiated. The method is not declared as public/protected/private, so it's public by default, therefore accessible by parents/children as well as from the outside.
Of course, this is generally poor coding style, at least A would demand the implementation of __ in child classes with the following line: abstract public function __();.
Last, but not least, the function name __ is against PHP conventions, as methods starting with two underscores are reserved.
I would describe PHP as a language that tends to make assumptions when things are unclear, whereas C++ and Java are languages that force you to explicitly write everything out, or else they will throw errors.
Question #1 - In PHP you do not explicitly need to declare class properties in order to be able to assign them later, as you have discovered. Obviously though, if you immediately tried to echo $this->var; inside a class without assigning it, it would be undefined.
Question #2 - So this one's a little weird, but basically, if you create a superclass from a subclass, and you call a method inside a method defined in the subclass, the superclass version will get called. So even though __() is not defined in A, it is in defined in B, so if you create an A object, and called echoVar(); you will get a message about the method __() is undefined, you can still call echoVar(); in an object of type B, as __(); is defined there.
Question #3 - Similar to #2, even when used in the subclass, the superclass version of variables will be used.
I personally would try to never use this style of coding, however. As I'm sure you're already aware, it's not a good idea to make a class dependent on its superclass like that. It would be better to explicitly declare these things.
As for how it is OOP, the code you posted is primarily using objects as opposed to free floating functions or lines of code.

Is good to use static variable inside a PHP class method

I am doing a class "Container" to hold all my model/service instances, the class is a singleton.
Consider the following code portion (from a CodeIgniter project):
public function getReviewModel()
{
static $loaded = false;
if (!$loaded)
{
$this->load->model('review_model');
$loaded = true;
}
return $this->review_model;
}
I am wondering if is still ok to use static inside method like this or should I use only class property (I mean about performance and coding standard) ?
In your example, nothing prevents the programmer to instanciate the class more than once (with dire results), so it is rather a confusing bit of code.
Static variables have their uses, be them local to a function or defined at class level.
Especially in PHP scripts, when the output is often a single piece of data that can conveniently be handled as a class defining only static properties and methods.
That would be a true, foolproof singleton class.
Since mistaking a static variable for a dynamic one is a common pitfall, I tend to favor static class variables to avoid the confusion (i.e. the self::$... syntax makes them stand out clearly).
General consensus as far as statics are concerned in PHP is: Avoid, if at all possible. And yes, 99% of the time, it is possible to avoid statics.
Singletons should be avoided 100% of the time. For reasons you can find here and virtually everywhere else on the web. Singletons are like communism: sounds like a nice idea, but when put in to practice, it turns out there's one or two things you didn't anticipate.
A Singletons' main purpouse is to retain state, but PHP itself is stateless, so come the next request, the singleton needs to be re-initialized anyway.
If I write getters like yours, I tend to create them in a lazy-load kind of way:
class Example
{
private $reviewModel = null;//create property
public function getReviewModel()
{
if ($this->reviewModel === null)
{//load once the method is called, the first time
$this->reviewModel = $this->load->model('review_model');
}
return $this->reviewModel;
}
}
This basically does the same thing, without using statics. Because I'm using a property, I still retain the instance, so if the getReviewModel method is called again, the load->model call is skipped, just as it would be using a static.
However, since you're asking about performance as well as coding standards: statics are marginally slower than instance properties: Each instance has a HashTable containing for its properties, and a pointer to its definition. Statics reside in the latter, because they are shared by all instances, therefore a static property requires extra lookup work:
instance -> HashTable -> property
instance -> definition -> HashTable -> property
This isn't the full story, check answer + links here, but basically: the route to a static propery is longer.
As for coding standards: They exist, though still unofficial, most major players subscribe to them, and so should you: PHP-FIG
Things like $this->_protectedProperty; don't comply with the PSR-2 standard, for example, which states, quite unequivocally:
Property names SHOULD NOT be prefixed with a single underscore to indicate protected or private visibility.

Visibility of object constants

I found out that object constants in PHP always have public visibility so it is not possible to set them to protected or private like this:
<?php
class MyClass {
protected const constant = "this won't work";
}
?>
What's the explanation for this? I can't think of a good reason to force constants to be public.
That's a rather philosophical question, which is discussed in the comments for Class constants in the PHP Manual. The argument seems to be that Visibility identifies who has the right to change members, not who has the right to read them. Since constants cannot be changed, there is no point in having them support visibility when visibility is understood as access modifiers. If you follow that argumentation or go with the linked feature request below your question is up to you.
I can't think of a good reason to force constants to be public.
Well, constants are static definitions, bound to the class and not instantiated objects. They can be addressed only using classname::constname, and they cannot be altered. It stands to reason they are part of the blueprint of a class, and thus it doesn't really make sense to apply visibility rules to them.
That's just my rather subjective opinion, though. Interested to see whether anything based on hard OOP theory comes up.

What are static and dynamic variables / methods in OOP?

I am trying to better understand basic concepts in OOP.
What are static and dynamic variables and methods in object-oriented programming?
What is, for instance, the difference between using $this vs. double colon (::)?
$this ($this->a_method())
Advantages: ?.
Disadvantages: ? ... "this" is not self-documenting as in: $this->method_from_an_extended_class().
Double colon (someclass::a_method())
Advantages: ?
Disadvantages: ?
"Static" and "dynamic" aren't the right descriptions for that.
-> indicates a instance functions or instance data, meaning that the function or data has an implicit $this reference. To put it another way you're referring to the function or variable within a particular object.
:: indicates a class function or class variable. This is very similar to a global function or variable in that there is no implicit $this reference. All instance of that class share that function or variable.
"Dynamic" would be a more accurate description for, say, PHP overloading where you can "dynamically" create variables, for example, using the magic methods __get() and __set() (which are called when you try to access a property that can't be found; you can overload these methods to essentially pretend the requested member exists).
Quoting the static page in the PHP manual :
Declaring class properties or methods
as static makes them accessible
without needing an instantiation of
the class. A property declared as
static can not be accessed with an
instantiated class object (though a
static method can).
Also note that when declaring a property as static, there will be only one version of that property for the whole script : static methods/properties "act at the class level rather than at the instance level" (quoting wikipedia).
About advantages / disadvantages, it's a bit hard to answer clearly, as those are just not the same...
The question is : what do you need ?
If you have an object that contains data, and want methods to deal with that data, you'll use dynamic properties and methods.
On the other hand, if you just want to use a class as container for methods that deal with external data (ie, not internal to the class), you'll probably use static methods.
For instance, I am sometimes using static methods as wrappers to libraries that don't export an Oriented-Object API : it allows me to call one class::method, instead of several functions.
Some would say an "advantage" of static methods is that you don't need to instanciate the class to use them -- that is true ; but it also means that you don't get objects, with methods working on them ; well : as I said, using static or not depends on what you need.
Oh, I almost forgot : if you are willing to use unit-testing, you might find out that static methods are not easy to test ; for instance, see Static Methods are Death to Testability.
And static properties (same with singleton and registry design patterns, which rely on static properties/methods) kind of imply "global state", like "global variables" -- which some don't quite like ^^

Categories