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:
The
$articles
property is only defined in theArticle
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 theInterview
andReport
classes are defined. There's only one time that an empty array is getting assigned - there's only one shared variable.You're using
self
in youradd_Object_To_Array()
method instead ofstatic
.self::
refers to the class it is defined in, so since youradd_Object_To_Array()
method is defined in theArticle
class, it'll refer to theArticle::$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 inadd_Object_To_Array()
referring to eitherReport::$articles
orInterview::$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
How Does Pcntl_Fork Work in PHP
Laravel Form HTML with Put Method for Put Routes
Generate Download File Link in PHP
Laravel 5.2: the Process Class Relies on Proc_Open, Which Is Not Available on Your PHP Installation
Unit Testing with Items That Need to Send Headers
Boolean Variables Posted Through Ajax Being Treated as Strings in Server Side
How to Convert Float Value to Integer in PHP
How to Set Curlopt_Cainfo Globally for PHP
Allow Users to Download Files Outside Webroot
What Does [\S\S]* Mean in Regex in PHP
Create Superglobal Variables in PHP
Include PHP File into HTML File
Laravel Error: Method Illuminate\View\View::_Tostring() Must Not Throw an Exception
PHP Put a Space in Front of Capitals in a String (Regex)
PHP Exec() Not Returning Error Message in Output
Get Only Filename from Url in PHP Without Any Variable Values Which Exist in the Url