I realize that this question has already been asked elsewhere for different programming languages... But this is not a 100% indicator for the same answer in the PHP domain, so I am asking this question.
Could someone please tell me what, specifically in PHP, is the difference between "final static" and "const" ?
final
The methods or classes can not be modified by a child class. This prevents class inheritance, method-overriding and/or redefinition of methods.
Only class definitions and/or methods inside a class can be defined as
final.
static
Declares class methods or properties as a static value so that you have access to them without instantiating an object. These are shared between parent and child-classes.
A class definition can not be static unlike final.
const
These create a constant value for a class. The constant values will get changed and can NOT be changed by a method in either parent or child-class.
Class constants are allocated per instance of the class.
const is a type specifier in itself. It can not be put along with public/private/static etc. final, as mentioned before can be used along with any method or class definitions and hence; applicable with all of them. static can not be applied to class definitions but can be used for class properties.
UPDATE
modifiers are allowed for class constants since PHP 7.1.0.
class Foo {
public const bar = 5;
private const baz = 6;
}
To summarise, final static can not be used to define something like:
class X {
final static x = 5;
}
which is why you have a const.
final is not for class properties, only classes and methods. It means that the method cannot be overridden, or that the class cannot be inherited from. const is the PHP equivalent to a Java final variable.
They don't have anything at all in common, and they create completely different kinds of things. const declares a constant. final static declares a method which is static (can be called without an instance of the class) and final (can't be overridden by subclasses). static alone can be used to define a class-scoped variable, which isn't constant (but variables can't be final).
Related
I don't understand why the following code works. Isn't STEALTH being redefined in the subclass... although it is declared as const in the parent? FYI, I was under the impression that const prevents the variable from being redefined!
class Person {
const STEALTH = "MINIMUM";
}
class Ninja extends Person {
const STEALTH = "MAXIMUM";
}
echo Ninja::STEALTH; // prints out 'MAXIMUM'
Please note that I am not asking about the scope resolution operator. I think I understand the difference between printing out Ninja::STEALTH vs Person::STEALTH. I am just surprised at the fact that ninja is able to inherit a const variable and yet have the ability to redefine it!
const merely means that the value cannot be altered at runtime. It does not restrict classes from independently defining a constant by the same name; the only thing is that inheritance rules will define when and how the parent's value may get shadowed by the child's.
I was under the impression that const prevents the variable from being redefined!
const prevents the value to be modified.
It is not possible to define two different objects that has the same name using define(). It is also not possible to define two different objects that has the same name using const. A const class member is always accessed using its full name (class name + :: + constant name).
The name of the STEALTH constant defined by the Person class is Person::STEALTH. The Ninja class declares the constant Ninja::STEALTH.
They are different objects.
const (and static) class properties are not inherited the same way instance properties are. If a const property defined by the base class is not masked by another object with the same name defined by the child class, the base class const property is copied in the child class and can be accessed using the child class name.
For example:
class Person {
const STEALTH = "MINIMUM";
}
class Citizen extends Person {
}
class Ninja extends Person {
const STEALTH = "MAXIMUM";
}
echo Person::STEALTH; // prints out 'MINIMUM'
echo Citizen::STEALTH; // prints out 'MINIMUM'; same as Person::STEALTH
echo Ninja::STEALTH; // prints out 'MAXIMUM'
Because class Citizen extends class Person and it doesn't define its own STEALTH constant, Citizen::STEALTH is a copy of Person::STEALTH1.
Class constants are global objects with fancy names (and class visibility modifiers since PHP 7.0).
I have a class with a variable $x that I want to use in a static function on his subclass.
class people{
protected $x;
function __constructor(){
$this->x = 'cool';
}
}
class person extended people {
function static status() {
'Here I want to use the x variable. I tried $this->x,parent::x..';
}
}
This obviously is not possible, since there is no object referred to inside a static method. That is the whole point of a static method: to be able to use it independent of an instantiated object. But without such object you obviously do not have a property $x...
There are a few alternatives, which one you chose depends on your situation:
you can hand over the value as an explicit argument (so static function status($x)), if you have access to the property of an instantiated object of class people.
you can declare the property as static const inside the class. In that case you obviously do have access from within a static class method. However it obviously is a constant that can be initialized, but which can not change its value over time.
you can design that property outside the class. Yes, this is obvious and changes the point of the class design. But since you already try to use a static method chances are that this method should not depend on any instantiated object at all...
In general one can say that the issue you ran into demonstrates that your class design is not conclusive, does not really make sense in itself in its current state. You will have to redesign the class (or maybe a bigger architecture).
Start by asking yourself a question: "why do you want to make the method status() static at all?"
PHP allows use of static member functions and variables, since 5.3 including late static bindings:
class StaticClass {
public static $staticVar;
...
}
$o = new StaticClass();
Currently, there are various options to access those static members:
$o->staticVar; // as instance variable/ function
$o::staticVar; // as class variable/ function
Other options exist for accessing members from inside the class:
self::$staticVar; // explicitly showing static usage of variable/ function
static::$staticVar; // allowing late static binding
Restructuring some existing classes that make some use of static members I've asked myself if there are best practices for working with static members in PHP?
Well, obviously, they all do different things.
$o->staticVar
This is invalid, since you cannot/should not access static properties with the instance property syntax.
StaticClass::$staticVar
This very plainly accesses a specific static variable on a very specific class.
$o::$staticVar
This accesses the static variable on the class that $o is an instance of. It's mostly used as a shorthand for the previous method and is equivalent in all respects. Obviously though, which class is used exactly depends on what class $o is an instance of.
self::$staticVar
This can be used only inside a class, and will always refer to the class that it's written in. It's a good idea to use this inside a class instead of StaticClass::$staticVar if the class refers to itself, since you don't need to worry about anything if you change the class name later. E.g.:
class Foo {
protected static $bar = 42;
public function baz() {
self::$bar; // good
Foo::$bar // the same, but should be avoided because it repeats the class name
}
}
static::$staticVar
This can also only be used inside a class and is basically the same as self above, but resolves with late static binding and may hence refer to a child class.
What the "best practice" is is debatable. I'd say you should always be as specific as necessary, but no more. $o::$staticVar and static::$staticVar both allow the class to vary through child classes, while self::$staticVar and StaticClass::$staticVar do not. Following the open/closed principle, it's a good idea to use the former, more variable method to allow for extensions.
Properties, both static and non-static, should also not be public to not break encapsulation.
Also see How Not To Kill Your Testability Using Statics.
First of all, don't use $this->staticVar. I am unsure when this changed (I believe PHP 5.4), but in recent versions it is no longer possible to retrieve static variables this way.
As for using late static binding, don't use it if you don't need it. The reason to use it would be if you plan to use inheritance and expect to change the value of the static variable in a derived class.
If I have a class structure with a value that can either be true or false, that doesn't change, currently implemented as variables would it be better to change them to constants, such as:
class Parent {
const BOOL_CONST = false;
...
}
class SomeChild extends Parent {
const BOOL_CONST = true;
...
}
Later I have an object which may be of any type in that class hierarchy, either the parent or one of its children, and some of the children may, like 'SomeChild' have overloaded the value to be true.
Is there some way I can access the constant without knowing the class? In other words can I do something like:
$object->BOOL_CONST
Or would it be better to leave these values as variables, even though they really shouldn't change?
UPDATE
I've reworded my question above to better express what I was attempting to ask.
Is there some way I can access the constant without knowing the class?
In other words can I do something like:
Yes, in order to reference a constant, you will want to use the following constructs:
self::NAME_OF_CONSTANT: give me a constant defined in this class; if I don't define it, get it from my parent
static::NAME_OF_CONSTANT: give me a constant defined in this class ONLY; never look to my parent for it
parent::NAME_OF_CONSTANT: give me a constant defined in my parent class ONLY; never look to myself for it
BTW, you used the term "overloaded"; however, I believe you meant to say "overridden". Overloading has a different semantic meaning in object oriented languages.
Constant as access with the double colon ::
Parent::BOOL_CONST
SomeChild::BOOL_CONST
within the class
parent::BOOL_CONST
self::BOOL_CONST
PHP 5.3 now accepts the object as the class reference: $this::BOOL_CONST is now accepted.
//
// http://php.net/manual/en/language.oop5.constants.php
//
// As of PHP 5.3.0, it's possible to
// reference the class using a variable.
// The variable's value can not be a keyword
// (e.g. self, parent and static).
//
// I renamed "Parent" class name to "constantes"
// because the classname "Parent" can be confused with "parent::" scope
class constantes
{
const test = false;
}
// I renamed "SomeChild" too, with no reason...
class OverloadConst extends constantes
{
const test = true;
public function waysToGetTheConstant()
{
var_dump(array('$this'=>$this::test)); // true, also usable outside the class
var_dump(array('self::'=>self::test)); // true, only usable inside the class
var_dump(array('parent::'=>parent::test)); // false, only usable inside the class
var_dump(array('static::'=>static::test)); // true, should be in class's static methods, see http://php.net/manual/en/language.oop5.late-static-bindings.php
}
}
// Classic way: use the class name
var_dump(array('Using classname' => OverloadConst::test));
// PHP 5.3 way: use the object
$object = new OverloadConst();
var_dump(array('Using object' => $object::test));
$object->waysToGetTheConstant();
Note that you can override a class constant, but not an interface constant.
If constantes is an interface that OverloadConsts implements, then you can not override its const test (or BOOL_CONST).
Sources
Constants in PHP 5.3: http://php.net/manual/en/language.oop5.constants.php
Late static Binding: http://php.net/manual/en/language.oop5.late-static-bindings.php
No, you can't access constants from an object context, but you could use reflection to grab the class of $object and then use :: to get BOOL_CONST. So:
$class = get_class($object);
$class::BOOL_CONST;
Okay, no, that's not technically reflection. Also, I'm not 100% sure if $class:: will resolve correctly. Use the actual ReflectionClass classes if the above doesn't work.
You cannot do $object->BOOL_CONST, since class constants have to be called statically (SomeChild::BOOLCONSTANT).
However, maybe you can try something like that: // edit: this works :)
$class = get_class($object);
$const = $class::BOOL_CONST;
I am learning about OO and classes, I have a couple of questions about OO and classes in PHP
As I understand it, a class that extends another class simply means that the class that extends the other class has access to the variables/properties and the functions/methods of the class that it is extending from. Is this correct?
I know that a static method or property are basically the same as a procedural function or variable outside of a class and can be used pretty much anywhere. Is this correct?
Public means any class can access it and Private means only the class that is is encapsulated in or a class that is extended from the owner of can access and use. Is this correct?
1) Yes, that's correct. A child class inherits any protected or public properties and methods of its parent. Anything declared private can not be used.
2) This is true. As long as the class is loaded (this goes well with your autoloading question from before), you can access static methods via the scope resolution operator (::), like this: ClassName::methodName();
3) You have the meaning of public correct, but as I mentioned earlier, private methods can only be used by the class they are declared in.
class parentClass
{
private $x;
public $y;
}
class childClass extends parentClass
{
public function __construct() {
echo $this->x;
}
}
$z = new childClass();
The above code will result in a NOTICE error being triggered, as $x is not accessible by childClass.
Notice: Undefined property:
childClass::$x
If $x was declared protected instead, then childClass would have access. Edit: A property declared as protected is accessible by the class that declares it and by any child classes that extend it, but not to the "outside world" otherwise. It's a nice intermediate between public and private.
For 1. As I understand it, a class that extends another class simply means that the class that extends the other class has access to the variables/properties and the functions/methods of the class that it is extending from. Is this correct?
ANS: That is correct but that is not all. The extending class can also customize the extended class by overriding the method of the extended class. And ofcouse, it can also extend the super class functionality by adding new fields and methods.
For 2. I know that a static method or property are basically the same as a procedural function or variable outside of a class and can be used pretty much anywhere. Is this correct?
ANS: Yes that is correct and as zombat said as long as the class is public and loaded and the property and method is public. In other word, you are using the class as name space of those elements.
For 3. Public means any class can access it and Private means only the class that is is encapsulated in or a class that is extended from the owner of can access and use. Is this correct?
ANS: Think of it as physical properties, public computer (at a library) can be used by everyone and your private computer (supposibly) can only be used by you.
Just to added to Zambat comment.
There's very little need to declare anything private, as a general rule use protected instead.