Inheritance of Static Members in PHP

Inheritance of static members in PHP

Classic example of why using statics as globals (functions in this case) is a bad idea no matter the language.

The most robust method is to create multiple implementation sub classes of an abstract base "Action" class.

Then to try and remove some of the annoyance of instantiating an instance of the class just to call it's methods, you can wrap it in a factory of some sort.

For example:

abstract class AbstractAction {
public abstract function do();
}

class FooAction extends AbstractAction {
public function do() {
echo "Do Foo Action";
}
}

class BarAction extends AbstractAction {
public function do() {
echo "Do Bar Action";
}
}

Then create a factory to "aid" in instantiation of the function

class ActionFactory {
public static function get($action_name) {
//... return AbstractAction instance here
}
}

Then use it as:

ActionFactory::get('foo')->do();

PHP: Sub class static inheritance - children share static variables?

Everything is going into only one array for two reasons:

  1. The $articles property is only defined in the Article class.

    Static class properties do not get inherited the same way you might expect if you're used to non-static properties. While they are available to the child classes, they're still referencing a single variable on the parent class - resulting in the behavior you're seeing here where both child classes are sharing the same array.

    The only way to prevent this is to define a separate array in each of your child classes, like this:

    class Report extends Article {
    public static $articles = array();
    }
    class Interview extends Article {
    public static $articles = array();
    }

    This actually makes sense if you think of the static variable declarations as code that gets run when the class is defined. Creating a static variable and assigning an empty array to it happens when the Article class is defined. It doesn't happen again when the Interview and Report classes are defined. There's only one time that an empty array is getting assigned - there's only one shared variable.

  2. You're using self in your add_Object_To_Array() method instead of static.

    • self:: refers to the class it is defined in, so since your add_Object_To_Array() method is defined in the Article class, it'll refer to the Article::$articles array.

    • static:: Is available starting in PHP 5.3, and refers to the class it is called on. This is known as Late Static Binding, and will result in add_Object_To_Array() referring to either Report::$articles or Interview::$articles depending on the type of the object you're calling it on.

    This code will reference the two arrays that we declared in the first step:

    public function add_Object_To_Array() {
    array_push(static::$articles, $this);
    }

PHP Class inheritance and static members, the proper way of doing things

Here's a solution:

public function isValidField($name) {
$class = get_class($this);
return in_array(strtolower($name), $class::$db_to_obj);
}

override a static variable

The principle is called "late static binding", and was introduced in PHP 5.3.0; with the self keyword to access the property defined in the calling class within the inheritance tree, or static to access the property defined in the child class within that inheritance tree.

class person
{
protected static $todo ="nothing";

public function __construct(){}

public function get_what_todo()
{
echo static::$todo; // change self:: to static::
}
}

class student extends person
{
protected static $todo ="studying";
}

class teacher extends person
{
protected static $todo ="marking";
}

class guest extends person
{
}

$s = new student();
$s->get_what_todo(); // this will show the "studying" from the instantiated child class

$t = new teacher();
$t->get_what_todo(); // this will show the "marking" from the instantiated child class

$g = new guest();
$g->get_what_todo(); // this will show the "nothing" from the parent class,
// because $todo is not overriden in the child class

Static properties on base class and inheritance

I am thinking this stems from the fact that only one static::$values will ever be created and both assume I am referencing that value.

Correct.

This can be fixed by re-declaring public static $values on each of the classes which extends from the base, but is there a simpler way to do this such that each gets their own static copy? Any keywords or tricks that will prevent the need to re-declare on each inherited class?

No, there isn't anything like that. However, what does the trick is to avoid static stuff as much as possible. When you run into a situation like this one, that's most of the time a good indicator that your code design needs some optimization.

Class inheritance in PHP with Singleton Pattern only works if the instance variable in the inherited class is reinitialized. But why?

In your first part it is working correct and as expected. Both classes sub11 and sub12 using base1's field to store instance. So, the first one, which was instatiated, is placed there and preventing others to overwrite already created instance.

In second part, you specified personal static storage field for each descendant classes, so they uses not base class field, but own field instead (it overlaps parent field, as uses same name).

In a short, first pair of descendant classes uses base1::$instance to check and create instance. Second pair uses own fields, sub21::$instance and sub22::$instance for this task.

You can prevent this by discarding late static binding in base1 class:

class base1
{
/*
* Instance of class
* mixed
*/
protected static $instance = null;

/*
* For Singleton Pattern
*/
public static function instance() {
if ( null == self::$instance ) {
// ^ self instead of static
self::$instance = new static();
// ^ self instead of static
}

return self::$instance;
// ^ self instead of static
}

public function test()
{
$test = "base1";
var_dump($test);
}
}

I do really suggest you to read about late static binding and difference between self and static keywords.

UPDv1:

If you still requiring to get only one instance of each descendant class, you can change singleton method to something like this:

class base1
{
/*
* Instances of descendant classes
* array
*/
protected static $instances = [];

/*
* For Singleton Pattern
*/
public static function instance() {
if (empty(self::$instances[static::class])) {
$instance = new static();

self::$instances[static::class] = $instance;
} else {
$instance = self::$instances[static::class];
}

return $instance;
}

public function test()
{
$test = "base1";
var_dump($test);
}
}

Static counter of subclass instances in PHP

A lot depends on where you define the count and how you access it. If you have 1 count in the base class, then there is only 1 count. If you have a count in each class, then you need to be aware of how to access the right value. Using self or static is discussed more What is the difference between self::$bar and static::$bar in PHP?

class Vehicle
{
protected static $_count=0;

public static function getCount() {
return static::$_count;
}

public function __construct($type, $year)
{
// Access the count in the current class (Bike or Car).
static::$_count++;
// Access the count in this class
self::$_count++;
}
}

class Bike extends Vehicle
{
protected static $_count=0;
}

class Car extends Vehicle
{
protected static $_count=0;
}

This has both, and in the constructor, it increments them both. This means there is a total of all vehicles and of each type...

echo "Vehicle::getCount()=".Vehicle::getCount().PHP_EOL;
echo "Car::getCount()=".Car::getCount().PHP_EOL;
echo "Bike::getCount()=".Bike::getCount().PHP_EOL;
$a = new Car("a", 1);
echo "Vehicle::getCount()=".Vehicle::getCount().PHP_EOL;
echo "Car::getCount()=".Car::getCount().PHP_EOL;
echo "Bike::getCount()=".Bike::getCount().PHP_EOL;
$a = new Bike("a", 1);
echo "Vehicle::getCount()=".Vehicle::getCount().PHP_EOL;
echo "Car::getCount()=".Car::getCount().PHP_EOL;
echo "Bike::getCount()=".Bike::getCount().PHP_EOL;

gives (not very clear though)...

Vehicle::getCount()=0
Car::getCount()=0
Bike::getCount()=0
Vehicle::getCount()=1
Car::getCount()=1
Bike::getCount()=0
Vehicle::getCount()=2
Car::getCount()=1
Bike::getCount()=1

How to know if static property is inherited in php?

You can use the ReflectionClass with the method getProperties to retrieves the reflected properties. To filter you can use ReflectionProperty

<?php

class A
{
static $foo = 42;
static $baz = 4;
}

class B extends A
{
static $bar = 2;
static $baz = 44;
}

function isOwnStaticProperty($class, $prop) {
$reflect = new ReflectionClass($class);
//Filtering only the statics values with ReflectionProperty::IS_STATIC
$props = $reflect->getProperties(ReflectionProperty::IS_STATIC);
foreach ($props as $object) {
if($object->class == $class && $object->name == $prop) {
return true;
}
}
return false;
}

$class_name = 'A';
echo isOwnStaticProperty($class_name, 'foo') ? "TRUE<br>\n" : "FALSE<br>\n";

$class_name = 'B';
echo isOwnStaticProperty($class_name, 'foo') ? "TRUE<br>\n" : "FALSE<br>\n";

$class_name = 'B';
echo isOwnStaticProperty($class_name, 'bar') ? "TRUE<br>\n" : "FALSE<br>\n";

$class_name = 'A';
echo isOwnStaticProperty($class_name, 'bar') ? "TRUE<br>\n" : "FALSE<br>\n";

$class_name = 'B';
echo isOwnStaticProperty($class_name, 'baz') ? "TRUE<br>\n" : "FALSE<br>\n";

$class_name = 'A';
echo isOwnStaticProperty($class_name, 'baz') ? "TRUE<br>\n" : "FALSE<br>\n";

OUTPUT:

TRUE

FALSE

TRUE

FALSE

TRUE

TRUE



Related Topics



Leave a reply



Submit