PHP Inheritance and Static Methods and Properties - php

Is it safe to say that static properties and methods can not be inherited in PHP? a few examples will be helpful.

No. That's not true. Static Methods and properties will get inherited the same as non-static methods and properties and obey the same visibility rules:
class A {
static private $a = 1;
static protected $b = 2;
static public $c = 3;
public static function getA()
{
return self::$a;
}
}
class B extends A {
public static function getB()
{
return self::$b;
}
}
echo B::getA(); // 1 - called inherited method getA from class A
echo B::getB(); // 2 - accessed inherited property $b from class A
echo A::$c++; // 3 - incremented public property C in class A
echo B::$c++; // 4 - because it was incremented previously in A
echo A::$c; // 5 - because it was incremented previously in B
Those last two are the notable difference. Incrementing an inherited static property in the base class will also increment it in all the child classes and vice versa.

No (Apparently I couldn't see the not in the question). public and protected static methods and properties are inherited as you would expect them to be:
<?php
class StackExchange {
public static $URL;
protected static $code;
private static $revenue;
public static function exchange() {}
protected static function stack() {}
private static function overflow() {}
}
class StackOverflow extends StackExchange {
public static function debug() {
//Inherited static methods...
self::exchange(); //Also works
self::stack(); //Works
self::overflow(); //But this won't
//Inherited static properties
echo self::$URL; //Works
echo self::$code; //Works
echo self::$revenue; //Fails
}
}
StackOverflow::debug();
?>
Static properties and methods obey the visibility and inheritance rules as illustrated in this snippet.

Related

static property sharing/defining between children in PHP classes

I'm facing a misunderstanding about what the title describe and i'd like to know if there is another way to achieve what I'm looking for there.
I have an abstract class which declare a static property without value, and I instanciate subclasses from it that are defining the value of that static property. The base class also define another static property value depending of the first one, but the problem is subclasses are losing their first property value for the last one defined in other subclasses and then this second property get the bad value from the parent class.
This code demonstrate it better than I explain:
abstract class A
{
protected static $name;
protected static $path;
public function __construct()
{
static::$path = static::$name."Path";
}
public function getPath()
{
return static::$path;
}
}
class B extends A
{
protected static $name = "B";
}
class C extends A
{
protected static $name = "C";
}
$b = new B();
$c = new C();
echo $b->getPath();
I expected the echo to print "Bpath", but unfortunately it prints "CPath".
If I comment the line that instanciate the C class, then the print is good.
EDIT:
The thing is if i do this code :
abstract class A
{
protected static $name;
protected static $path;
public function __construct()
{
static::$path = static::$name."Path";
}
public function getPath()
{
return static::$path;
}
public function getName()
{
return static::$name;
}
}
class B extends A
{
protected static $name = "B";
}
class C extends A
{
protected static $name = "C";
}
$b = new B();
$c = new C();
echo $b->getName();
The name printed is "B" and good. So the fact of redefining value in subclass property doesn't have the same consequence of doing it in constructor, even if using static:: keyword.
The static property $path is only defined once on class A. Setting static::$path from anywhere will always set A::$path, so the value is shared among all classes.
You'd see a different result if you declared protected static $path; on both child classes, e.g.:
class B extends A {
protected static $name = "B";
protected static $path;
}
Now each class would have its own static $path property and they could be set independently.
It would make much more sense to use an instance property though instead of this bending over backwards with static properties:
abstract class A {
protected static $name;
protected $path;
public function __construct() {
$this->path = static::$name . 'Path';
}
public function getPath() {
return $this->path;
}
}

PHP function `get_object_vars` doesn't get private vars from inherited method

In this example I supposed that function getVars called from data would be able to return private vars names of Bdue to $this is an instance of B.
Instead of it, $this->getVars() returns an empty array.
Isn't get_object_vars called been private variables visible?
Isn't getVars a method inherited to B and called as if it was declared in it?
How can I get private variable names from a method declared in
an abstract class?
Example:
abstract class A
{
public function getVars()
{
return get_object_vars($this);
}
}
class B extends A
{
private $a;
private $b;
private $c;
public function data()
{
...
foreach($this->getVars() as $var) {
...
}
}
}
Private properties are only available to that class's methods. Try using protected properties to ensure the inherited methods have access to them.
The visibility of a property or method can be defined by prefixing the declaration with the keywords public, protected or private. Class members declared public can be accessed everywhere. Members declared protected can be accessed only within the class itself and by inherited classes. Members declared as private may only be accessed by the class that defines the member.
http://php.net/manual/en/language.oop5.visibility.php
Yes because get_object_vars is scope sensitive. If you don't wish to change the visibility of the variables then call get_object_vars directly from function data().
If you want to keep the code inheritance as it is, you'll have to change the visibility of the variables to protected.
abstract class A
{
public function getVars()
{
return get_object_vars($this);
}
}
class B extends A
{
protected $a;
protected $b;
protected $c;
public function data()
{
return $this->getVars();
}
}
$a = new B();
print_r($a->data());

Explanation of PHP class members visibility and inheritance

Consider the following snippet:
Class A {
private $a = 'foo';
public function F() {
return $this->a;
}
}
Class B extends A {
private $a = 'bar';
}
echo (new B)->F();
The result is foo. Well, it's a fait accompli that php works this way. But I wonder why. If in parent's method F() declaration I use pseudo-variable $this, it refers to object context. So when I call child inherited method F() $this variable means current instance of B with private $a = 'bar', doesn't it?
Update
Thanks AbraCadaver for your reply.
One circumstance is still unclear for me: if $this variable is an object of B during call of F(), how can it access parent's private member?
Did I understand correctly that $this within parent's method implementation is something similar to:
public function F(B $obj) {
return $obj->a;
}
So interpreter checks property visibility from parent class and in case of private scope it subsitutes B $obj for A $obj
From PHP: Visibility:
Members declared
protected can be accessed only within the class itself and by
inherited and parent classes. Members declared as private may only be
accessed by the class that defines the member.
In your example, regardless of the object being of class B, class A cannot access a private property of another class.
Also, if B has a protected property, that cannot override the class A property because it is private.
Both your example and the following yield foo:
Class A {
private $a = 'foo';
public function F() {
return $this->a;
}
}
Class B extends A {
protected $a = 'bar';
public function F() {
return parent::F();
}
}
echo (new B)->F();
However, if class A is also protected then it can be overridden by class B and class A has access to the property in class B.
Yields bar:
Class A {
protected $a = 'foo';
public function F() {
return $this->a;
}
}
Class B extends A {
protected $a = 'bar';
public function F() {
return parent::F();
}
}
echo (new B)->F();

What is the difference between self::$bar and static::$bar in PHP?

What is the difference between using self and static in the example below?
class Foo
{
protected static $bar = 1234;
public static function instance()
{
echo self::$bar;
echo "\n";
echo static::$bar;
}
}
Foo::instance();
produces
1234
1234
When you use self to refer to a class member, you're referring to the class within which you use the keyword. In this case, your Foo class defines a protected static property called $bar. When you use self in the Foo class to refer to the property, you're referencing the same class.
Therefore if you tried to use self::$bar elsewhere in your Foo class but you had a Bar class with a different value for the property, it would use Foo::$bar instead of Bar::$bar, which may not be what you intend:
class Foo
{
protected static $bar = 1234;
}
class Bar extends Foo
{
protected static $bar = 4321;
}
When you call a method via static, you're invoking a feature called late static bindings (introduced in PHP 5.3).
In the above scenario, using self will result in Foo::$bar(1234).
And using static will result in Bar::$bar (4321) because with static, the interpreter takes into account the redeclaration within the Bar class during runtime.
// self
var_dump(Foo::$bar);
// (int) 1234
// static
var_dump(Bar::$bar);
// (int) 4321
You typically use late static bindings for methods or even the class itself, rather than properties, as you don't often redeclare properties in subclasses; an example of using the static keyword for invoking a late-bound constructor can be found in this related question: New self vs. new static
However, that doesn't preclude using static with properties as well.
I have small example showing difference between self and static. Using static:: performs Late Static Binding and thus it binds the variable value from child class.
class A { // Base Class
protected static $name = 'ClassA';
public static function getSelfName() {
return self::$name;
}
public static function getStaticName() {
return static::$name;
}
}
class B extends A {
protected static $name = 'ClassB';
}
echo A::getSelfName(); // ClassA
echo A::getStaticName(); // ClassA
echo B::getSelfName(); // ClassA
echo B::getStaticName(); // ClassB
With self call:
class Phone
{
protected static $number = 123;
public function getNumber()
{
return self::$number;
}
}
class Fax extends Phone
{
protected static $number = 234;
}
// Displays: "123"
echo (new Fax)->getNumber();
You can see above, even though we have overridden the $number with our Fax class, getNumber() still returns 123.
This because we have asked PHP to give us the variable where it was defined in -- which will return Phones variable instead.
If we swap the self call with static, we will get Faxs overridden value instead:
With static call:
class Phone
{
protected static $number = 123;
public function getNumber()
{
// return self::$number;
return static::$number;
}
}
class Fax extends Phone
{
protected static $number = 234;
}
// Displays: "234"
echo (new Fax)->getNumber();
As mentioned one of the main differences is that static allows for late static bindings. One of the most useful scenarios that I found was for creating Base classes for Singleton Classes:
class A { // Base Class
protected static $name = '';
protected static function getName() {
return static::$name;
}
}
class B extends A {
protected static $name = 'MyCustomNameB';
}
class C extends A {
protected static $name = 'MyCustomNameC';
}
echo B::getName(); // MyCustomNameB
echo C::getName(); // MyCustomNameC
Using return static::$name in the Base class will return what was statically attached when it was extended. If you were to use return self::$name then B::getName() would return an empty string as that is what is declared in the Base class.
Maybe this self-explained code helps you:
class Foo
{
protected static $bar = 'parent value';
public static function test()
{
var_dump('I am your father');
var_dump('self:: here means '.self::$bar);
var_dump('static:: here means '.static::$bar);
}
}
class Bar extends Foo
{
protected static $bar = 'child value';
public static function test()
{
parent::Test();
var_dump('I am the child');
var_dump('self:: here means '.self::$bar);
var_dump('static:: here means '.static::$bar);
}
}
Bar::test();
Foo::test();
This produces the following output (I have added Line Breaks for clarity):
'I am your father' (length=16)
'self:: here means parent value' (length=30)
'static:: here means child value' (length=31)
'I am the child' (length=14)
'self:: here means child value' (length=29)
'static:: here means child value' (length=31)
'I am your father' (length=16)
'self:: here means parent value' (length=30)
'static:: here means parent value' (length=32)

Why doesn't late static binding work with variables in PHP 5.3?

Let's start off with some code:
class Super {
protected static $color;
public static function setColor($color){
self::$color = $color;
}
public static function getColor() {
return self::$color;
}
}
class ChildA extends Super { }
class ChildB extends Super { }
ChildA::setColor('red');
ChildB::setColor('green');
echo ChildA::getColor();
echo ChildB::getColor();
Now, late static binding in PHP 5.3 using the static keyword works great with static methods, so I assumed it would do the same magic on static variables. Well, seems it doesn't. The example above does not print out "red" and then "green" as I first expected, but "green" and "green". Why doesn't this work on variables when it works on methods? Is there any other way to achieve the effect I expected?
Late static binding will only work for new definitions of variables / methods. Thus, in your example, the $color property of Super will always be modified instead of ChildA or ChildB. To make use of late static binding, you need to use the static keyword instead of self. Furthermore, you need to redefine the $color property of your ChildA and ChildB classes:
class Super {
protected static $color;
public static function setColor($color){
// static instead of self
static::$color = $color;
}
public static function getColor() {
// static instead of self
return static::$color;
}
}
class ChildA extends Super {
protected static $color;
}
class ChildB extends Super {
protected static $color;
}
ChildA::setColor('red');
ChildB::setColor('green');
echo Super::getColor(); // prints nothing (NULL = ''), expected
echo ChildA::getColor();// prints red
echo ChildB::getColor();// prints green

Categories