Static counter of subclass instances in PHP - php

I'm aware of a pattern for adding a static counter to a class to count the number of instances of that class
class Vehicle
{
private static $_count=0;
public static function getCount() {
return self::$_count;
}
public function __construct()
{
self::$_count++;
}
}
What I would like to do is to add a couple of subclasses to Vehicle and count instances of those independently
class Bike extends Vehicle
{
...
}
class Car extends Vehicle
{
...
}
So calling Bike::getCount() and Car::getCount() would get the count of the number of Bikes and Cars respectively
Is this possible without
repeating code in the subclasses?
setting up some kind of counting array keyed by class name in the superclass?

You can keep an array of counts in the parent class rather than just a single integer, indexed using static:class. This will reference the class name of the current instance, unlike self::, which always references the class in which it's being used.
class Vehicle
{
private static $counts = [];
public static function getCount()
{
return self::$counts[static::class];
}
public function __construct()
{
// Using a reference here to avoid undefined-index notices
$target =& self::$counts[static::class];
$target++;
}
}
class Bike extends Vehicle {}
new Bike;
var_dump(Bike::getCount());
// int(1)
Full demo here: https://3v4l.org/Qibd7
I'd also agree with #u_mulder's comment that this is a bit of an unusual pattern. A class definition should only be concerned with attributes of a single instance, and not store global state. Maintaining a collection of instances (even in a plain PHP array) would mean that you could count them independently. But that's up to you.

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

Related

How to implement abstract properties in PHP? [duplicate]

Is there any way to define abstract class properties in PHP?
abstract class Foo_Abstract {
abstract public $tablename;
}
class Foo extends Foo_Abstract {
//Foo must 'implement' $property
public $tablename = 'users';
}
There is no such thing as defining a property.
You can only declare properties because they are containers of data reserved in memory on initialization.
A function on the other hand can be declared (types, name, parameters) without being defined (function body missing) and thus, can be made abstract.
"Abstract" only indicates that something was declared but not defined and therefore before using it, you need to define it or it becomes useless.
No, there is no way to enforce that with the compiler, you'd have to use run-time checks (say, in the constructor) for the $tablename variable, e.g.:
class Foo_Abstract {
public final function __construct(/*whatever*/) {
if(!isset($this->tablename))
throw new LogicException(get_class($this) . ' must have a $tablename');
}
}
To enforce this for all derived classes of Foo_Abstract you would have to make Foo_Abstract's constructor final, preventing overriding.
You could declare an abstract getter instead:
abstract class Foo_Abstract {
abstract public function get_tablename();
}
class Foo extends Foo_Abstract {
protected $tablename = 'tablename';
public function get_tablename() {
return $this->tablename;
}
}
Depending on the context of the property, if I want to force declaration of an abstract class property in an extended class, I like to use a constant with the static keyword for the property in the abstract object constructor or setter/getter methods. You can optionally use final to prevent the method from being overridden in extended classes.
Example: https://3v4l.org/WH5Xl
abstract class AbstractFoo
{
public $bar;
final public function __construct()
{
$this->bar = static::BAR;
}
}
class Foo extends AbstractFoo
{
//const BAR = 'foobar'; //uncomment to prevent exception
}
$foo = new Foo();
//Fatal Error: Undefined class constant 'BAR'
However, the extended class overrides the parent class properties and methods if redefined.
For example; if a property is declared as protected in the parent and redefined as public in the extended class, the resulting property is public. Otherwise, if the property is declared private in the parent it will remain private and not available to the extended class.
http://www.php.net//manual/en/language.oop5.static.php
As stated above, there is no such exact definition.
I, however, use this simple workaround to force the child class to define the "abstract" property:
abstract class Father
{
public $name;
abstract protected function setName(); // now every child class must declare this
// function and thus declare the property
public function __construct()
{
$this->setName();
}
}
class Son extends Father
{
protected function setName()
{
$this->name = "son";
}
function __construct(){
parent::__construct();
}
}
The need for abstract properties can indicate design problems. While many of answers implement kind of Template method pattern and it works, it always looks kind of strange.
Let's take a look at the original example:
abstract class Foo_Abstract {
abstract public $tablename;
}
class Foo extends Foo_Abstract {
//Foo must 'implement' $property
public $tablename = 'users';
}
To mark something abstract is to indicate it a must-have thing. Well, a must-have value (in this case) is a required dependency, so it should be passed to the constructor during instantiation:
class Table
{
private $name;
public function __construct(string $name)
{
$this->name = $name;
}
public function name(): string
{
return $this->name;
}
}
Then if you actually want a more concrete named class you can inherit like so:
final class UsersTable extends Table
{
public function __construct()
{
parent::__construct('users');
}
}
This can be useful if you use DI container and have to pass different tables for different objects.
I've asked myself the same question today, and I'd like to add my two cents.
The reason we would like abstract properties is to make sure that subclasses define them and throw exceptions when they don't. In my specific case, I needed something that could work with statically.
Ideally I would like something like this:
abstract class A {
abstract protected static $prop;
}
class B extends A {
protected static $prop = 'B prop'; // $prop defined, B loads successfully
}
class C extends A {
// throws an exception when loading C for the first time because $prop
// is not defined.
}
I ended up with this implementation
abstract class A
{
// no $prop definition in A!
public static final function getProp()
{
return static::$prop;
}
}
class B extends A
{
protected static $prop = 'B prop';
}
class C extends A
{
}
As you can see, in A I don't define $prop, but I use it in a static getter. Therefore, the following code works
B::getProp();
// => 'B prop'
$b = new B();
$b->getProp();
// => 'B prop'
In C, on the other hand, I don't define $prop, so I get exceptions:
C::getProp();
// => Exception!
$c = new C();
$c->getProp();
// => Exception!
I must call the getProp() method to get the exception and I can't get it on class loading, but it is quite close to the desired behavior, at least in my case.
I define getProp() as final to avoid that some smart guy (aka myself in 6 months) is tempted to do
class D extends A {
public static function getProp() {
// really smart
}
}
D::getProp();
// => no exception...
As you could have found out by just testing your code:
Fatal error: Properties cannot be declared abstract in ... on line 3
No, there is not. Properties cannot be declared abstract in PHP.
However you can implement a getter/setter function abstract, this might be what you're looking for.
Properties aren't implemented (especially public properties), they just exist (or not):
$foo = new Foo;
$foo->publicProperty = 'Bar';
PHP 7 makes it quite a bit easier for making abstract "properties". Just as above, you will make them by creating abstract functions, but with PHP 7 you can define the return type for that function, which makes things a lot easier when you're building a base class that anyone can extend.
<?php
abstract class FooBase {
abstract public function FooProp(): string;
abstract public function BarProp(): BarClass;
public function foo() {
return $this->FooProp();
}
public function bar() {
return $this->BarProp()->name();
}
}
class BarClass {
public function name() {
return 'Bar!';
}
}
class FooClass extends FooBase {
public function FooProp(): string {
return 'Foo!';
}
public function BarProp(): BarClass {
// This would not work:
// return 'not working';
// But this will!
return new BarClass();
}
}
$test = new FooClass();
echo $test->foo() . PHP_EOL;
echo $test->bar() . PHP_EOL;
if tablename value will never change during the object's lifetime, following will be a simple yet safe implementation.
abstract class Foo_Abstract {
abstract protected function getTablename();
public function showTableName()
{
echo 'my table name is '.$this->getTablename();
}
}
class Foo extends Foo_Abstract {
//Foo must 'implement' getTablename()
protected function getTablename()
{
return 'users';
}
}
the key here is that the string value 'users' is specified and returned directly in getTablename() in child class implementation. The function mimics a "readonly" property.
This is fairly similar to a solution posted earlier on which uses an additional variable. I also like Marco's solution though it can be a bit more complicated.
Just define the property in the base class without assigning it a (default) value.
Getting the property value without redefining it with a default value or assigning it a value will throw an Error.
<?php
class Base {
protected string $name;
public function i_am() : string {
return $this->name;
}
}
class Wrong extends Base {
...
}
class Good extends Base {
protected string $name = 'Somebody';
}
$test = new Good();
echo $test->i_am(), '<br>'; // Will show "Nobody"
$test = new Wrong();
echo $test->i_am(), '<br>'; // Will throw an Error:
// Error: Typed property Base::$name must not be accessed before initialization in ....
?>
You can define a static property in an abstract class.
<?php
abstract class Foo {
private static $bar = "1234";
public static function func() {
echo self::$bar;
}
}
Foo::func(); // It will be printed 1234
Too late to answer the question, but you may use the difference between self and static as follows
<?php
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

PHP - Static property in extended/child class

If I have a base abstract class like so:
<?php
abstract class Record {
static $table;
public function getRows () {
return getRowsFromTable(static::$table);
}
}
?>
And I want to extend this class like so:
<?php
class User extends Record {
static $table = 'users';
private $name;
?>
Then if I call:
<?php
$user = new User;
$user->getRows();
?>
Internally, getRows() calls and returns getRowsFromTable('users').
But if I were to create another class that also extends Record:
<?php
class House extends Record {
static $table = 'houses';
private $address;
?>
Then that static $table = 'houses'; declaration overrides the Record::$table and, consequently, breaks the User class.
What's happening is, the declaration static $table = 'houses'; bubbles up to the parent class, so now Record::$table = 'houses';. Since House was declared after User, the next time I call $user->getRows(), internally, User references parent Record and ultimately calls getRowsFromTable('houses') instead of getRowsFromTable('users').
I'm using late static binding so as to get the property from the extended class; but since User and House extend the same parent class, they both end up with the same property value although they override it with different values.
If I were to duplicate the Record class by creating a class Record2 and having House extend Record2, I wouldn't have this problem -- but that wouldn't really help.
Is this the wrong setup? Should I not be using static variables in this context? What should I put in their place, if so? I know that $table doesn't necessarily have to be static, but there are other properties that may need to be static.
I really wouldn't use a static string for this purpose.
How about something like this...
abstract class Record {
/**
* #return table name as string
*/
abstract protected function getTable();
public function getRows () {
return getRowsFromTable($this->getTable());
}
}
Then, your concrete implementations would have to implement getTable, eg
class User extends Record {
protected function getTable() {
return 'users';
}
}

php class extends, variable from other extended class

I have a main class and two extended classes:
class Main {
public $foo;
}
class A extends Main {
public function setVar()
{
$foo = "test";
}
}
class B extends Main {
public function getVar()
{
return $this->foo;
}
}
$A = new A;
$B = new B;
$A->setVar();
echo "result: ".$B->getVar();
But result ($B->getVar()) stays empty. I am clearly missing something simple here... Besides that, is this the way to go splitting long classes up in relevant subclasses?
change:
class A extends Main {
public function setVar()
{
$foo = "test";
}
}
to:
class A extends Main {
public function setVar()
{
$this->foo = "test";
}
}
Notice the $this keyword
Example of using Dependency Injection (DI) to share an instance of Main between to different class instances rather than trying to use inheritence
class Main {
public $foo;
}
class A {
protected $main;
public function setVar($data)
{
$this->main->foo = $data;
}
public function __construct(Main $main)
{
$this->main = $main;
}
}
class B extends Main {
protected $main;
public function getVar()
{
return $this->main->foo;
}
public function __construct(Main $main)
{
$this->main = $main;
}
}
$M = new Main;
$A = new A($M);
$B = new B($M);
$A->setVar("test");
echo "result: ".$B->getVar();
To further clarify things, it may help to think it in this way. Let's say your Main is a class that stands for a vehicle (and hence we rename it Vehicle), so class means that Vehicle defines the characteristics of a veicle but not a particular one to do operations with (we need an instance for that).
Let's translate also your class A in Car and B in Truck: therefore they are specializations of your main class that, along with possessing every characteristic of a generic Vehicle, extend the concept of "vehicle" and point out specific behaviours and properties of Cars in general, and Trucks in general, but - and that's the point - don't reference a particular car or truck. We need instances for that.
class Vehicle
{
public $numberOfTires;
}
class Car extends Vehicle
{
function smashMe()
{
echo "Oops!";
}
}
class Truck extends Vehicle
{
function smashMe()
{
echo "More Oops!";
}
}
From this point we can define particular instances (your Porsche, my Camaro... different cars) on which we may perform operations (calling methods) and set properties.
$genericVehicle = new Vehicle;
$myPorsche = new Car;
$yourCamaro = new Car;
$hisTruck = new Truck;
$herTruck = new Truck;
But every instance remains independent from the other.
Both are different instances of the the same class.
Operations done on one instance, does not apply on any of the others (That's kinda the point of OOP).
To do what you want, You can have B extend A, and then perform both operations on a single instance of the B class.

PHP abstract properties

Is there any way to define abstract class properties in PHP?
abstract class Foo_Abstract {
abstract public $tablename;
}
class Foo extends Foo_Abstract {
//Foo must 'implement' $property
public $tablename = 'users';
}
There is no such thing as defining a property.
You can only declare properties because they are containers of data reserved in memory on initialization.
A function on the other hand can be declared (types, name, parameters) without being defined (function body missing) and thus, can be made abstract.
"Abstract" only indicates that something was declared but not defined and therefore before using it, you need to define it or it becomes useless.
No, there is no way to enforce that with the compiler, you'd have to use run-time checks (say, in the constructor) for the $tablename variable, e.g.:
class Foo_Abstract {
public final function __construct(/*whatever*/) {
if(!isset($this->tablename))
throw new LogicException(get_class($this) . ' must have a $tablename');
}
}
To enforce this for all derived classes of Foo_Abstract you would have to make Foo_Abstract's constructor final, preventing overriding.
You could declare an abstract getter instead:
abstract class Foo_Abstract {
abstract public function get_tablename();
}
class Foo extends Foo_Abstract {
protected $tablename = 'tablename';
public function get_tablename() {
return $this->tablename;
}
}
Depending on the context of the property, if I want to force declaration of an abstract class property in an extended class, I like to use a constant with the static keyword for the property in the abstract object constructor or setter/getter methods. You can optionally use final to prevent the method from being overridden in extended classes.
Example: https://3v4l.org/WH5Xl
abstract class AbstractFoo
{
public $bar;
final public function __construct()
{
$this->bar = static::BAR;
}
}
class Foo extends AbstractFoo
{
//const BAR = 'foobar'; //uncomment to prevent exception
}
$foo = new Foo();
//Fatal Error: Undefined class constant 'BAR'
However, the extended class overrides the parent class properties and methods if redefined.
For example; if a property is declared as protected in the parent and redefined as public in the extended class, the resulting property is public. Otherwise, if the property is declared private in the parent it will remain private and not available to the extended class.
http://www.php.net//manual/en/language.oop5.static.php
As stated above, there is no such exact definition.
I, however, use this simple workaround to force the child class to define the "abstract" property:
abstract class Father
{
public $name;
abstract protected function setName(); // now every child class must declare this
// function and thus declare the property
public function __construct()
{
$this->setName();
}
}
class Son extends Father
{
protected function setName()
{
$this->name = "son";
}
function __construct(){
parent::__construct();
}
}
The need for abstract properties can indicate design problems. While many of answers implement kind of Template method pattern and it works, it always looks kind of strange.
Let's take a look at the original example:
abstract class Foo_Abstract {
abstract public $tablename;
}
class Foo extends Foo_Abstract {
//Foo must 'implement' $property
public $tablename = 'users';
}
To mark something abstract is to indicate it a must-have thing. Well, a must-have value (in this case) is a required dependency, so it should be passed to the constructor during instantiation:
class Table
{
private $name;
public function __construct(string $name)
{
$this->name = $name;
}
public function name(): string
{
return $this->name;
}
}
Then if you actually want a more concrete named class you can inherit like so:
final class UsersTable extends Table
{
public function __construct()
{
parent::__construct('users');
}
}
This can be useful if you use DI container and have to pass different tables for different objects.
I've asked myself the same question today, and I'd like to add my two cents.
The reason we would like abstract properties is to make sure that subclasses define them and throw exceptions when they don't. In my specific case, I needed something that could work with statically.
Ideally I would like something like this:
abstract class A {
abstract protected static $prop;
}
class B extends A {
protected static $prop = 'B prop'; // $prop defined, B loads successfully
}
class C extends A {
// throws an exception when loading C for the first time because $prop
// is not defined.
}
I ended up with this implementation
abstract class A
{
// no $prop definition in A!
public static final function getProp()
{
return static::$prop;
}
}
class B extends A
{
protected static $prop = 'B prop';
}
class C extends A
{
}
As you can see, in A I don't define $prop, but I use it in a static getter. Therefore, the following code works
B::getProp();
// => 'B prop'
$b = new B();
$b->getProp();
// => 'B prop'
In C, on the other hand, I don't define $prop, so I get exceptions:
C::getProp();
// => Exception!
$c = new C();
$c->getProp();
// => Exception!
I must call the getProp() method to get the exception and I can't get it on class loading, but it is quite close to the desired behavior, at least in my case.
I define getProp() as final to avoid that some smart guy (aka myself in 6 months) is tempted to do
class D extends A {
public static function getProp() {
// really smart
}
}
D::getProp();
// => no exception...
As you could have found out by just testing your code:
Fatal error: Properties cannot be declared abstract in ... on line 3
No, there is not. Properties cannot be declared abstract in PHP.
However you can implement a getter/setter function abstract, this might be what you're looking for.
Properties aren't implemented (especially public properties), they just exist (or not):
$foo = new Foo;
$foo->publicProperty = 'Bar';
PHP 7 makes it quite a bit easier for making abstract "properties". Just as above, you will make them by creating abstract functions, but with PHP 7 you can define the return type for that function, which makes things a lot easier when you're building a base class that anyone can extend.
<?php
abstract class FooBase {
abstract public function FooProp(): string;
abstract public function BarProp(): BarClass;
public function foo() {
return $this->FooProp();
}
public function bar() {
return $this->BarProp()->name();
}
}
class BarClass {
public function name() {
return 'Bar!';
}
}
class FooClass extends FooBase {
public function FooProp(): string {
return 'Foo!';
}
public function BarProp(): BarClass {
// This would not work:
// return 'not working';
// But this will!
return new BarClass();
}
}
$test = new FooClass();
echo $test->foo() . PHP_EOL;
echo $test->bar() . PHP_EOL;
if tablename value will never change during the object's lifetime, following will be a simple yet safe implementation.
abstract class Foo_Abstract {
abstract protected function getTablename();
public function showTableName()
{
echo 'my table name is '.$this->getTablename();
}
}
class Foo extends Foo_Abstract {
//Foo must 'implement' getTablename()
protected function getTablename()
{
return 'users';
}
}
the key here is that the string value 'users' is specified and returned directly in getTablename() in child class implementation. The function mimics a "readonly" property.
This is fairly similar to a solution posted earlier on which uses an additional variable. I also like Marco's solution though it can be a bit more complicated.
Just define the property in the base class without assigning it a (default) value.
Getting the property value without redefining it with a default value or assigning it a value will throw an Error.
<?php
class Base {
protected string $name;
public function i_am() : string {
return $this->name;
}
}
class Wrong extends Base {
...
}
class Good extends Base {
protected string $name = 'Somebody';
}
$test = new Good();
echo $test->i_am(), '<br>'; // Will show "Nobody"
$test = new Wrong();
echo $test->i_am(), '<br>'; // Will throw an Error:
// Error: Typed property Base::$name must not be accessed before initialization in ....
?>
You can define a static property in an abstract class.
<?php
abstract class Foo {
private static $bar = "1234";
public static function func() {
echo self::$bar;
}
}
Foo::func(); // It will be printed 1234
Too late to answer the question, but you may use the difference between self and static as follows
<?php
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

What exactly are late static bindings in PHP?

What exactly are late static bindings in PHP?
You definitely need to read Late Static Bindings in the PHP manual. However, I'll try to give you a quick summary.
Basically, it boils down to the fact that the self keyword does not follow the same rules of inheritance. self always resolves to the class in which it is used. This means that if you make a method in a parent class and call it from a child class, self will not reference the child as you might expect.
Late static binding introduces a new use for the static keyword, which addresses this particular shortcoming. When you use static, it represents the class where you first use it, ie. it 'binds' to the runtime class.
Those are the two basic concepts behind it. The way self, parent and static operate when static is in play can be subtle, so rather than go in to more detail, I'd strongly recommend that you study the manual page examples. Once you understand the basics of each keyword, the examples are quite necessary to see what kind of results you're going to get.
From PHP: Late Static Bindings - Manual:
As of PHP 5.3.0, PHP implements a feature called late static binding which can be used to reference the called class in the context of static inheritance.
Late static binding tries to solve that limitation by introducing a keyword that references the class that was initially called at runtime. ... It was decided not to introduce a new keyword, but rather use static that was already reserved.
Let's see an example:
<?php
class Car
{
public static function run()
{
return static::getName();
}
private static function getName()
{
return 'Car';
}
}
class Toyota extends Car
{
public static function getName()
{
return 'Toyota';
}
}
echo Car::run(); // Output: Car
echo Toyota::run(); // Output: Toyota
?>
Late static bindings work by storing the class named in the last "non-forwarding call". In case of static method calls, this is the class explicitly named (usually the one on the left of the :: operator); in case of non-static method calls, it is the class of the object. A "forwarding call" is a static one that is introduced by self::, parent::, static::, or, if going up in the class hierarchy, forward_static_call(). The function get_called_class() can be used to retrieve a string with the name of the called class and static:: introduces its scope.
There is not very obvious behavior:
The following code produces 'alphabeta'.
class alpha {
function classname(){
return __CLASS__;
}
function selfname(){
return self::classname();
}
function staticname(){
return static::classname();
}
}
class beta extends alpha {
function classname(){
return __CLASS__;
}
}
$beta = new beta();
echo $beta->selfname(); // Output: alpha
echo $beta->staticname(); // Output: beta
However, if we remove the declaration of the classname function from the beta class, we get 'alphaalpha' as the result.
I'm quoting from the book: "PHP Master write cutting-edge code".
Late static binding was a feature introduced with php 5.3. It allows
us to inherit static methods from a parent class, and to reference
the child class being called.
This means you can have an abstract class with static methods, and
reference the child class's concrete implementations by using the
static::method() notation instead of the self::method().
Feel free to take a look at the official php documentation as well:
http://php.net/manual/en/language.oop5.late-static-bindings.php
The clearest way to explain Late Static Binding is with a practicle example. I'm using it in a Template method pattern. See below.
abstract class AbstractTemplate {
public const AWESOME_LIST = [''];
public function someFunction(): void {
$awesomeList = $this->getAwesomeList();
// OUTPUT: ['harry','henk','john'];
var_dump($awesomeList);
}
/**
* This function gets static constants from CHILD classes
*/
public function getAwesomeList(): array
{
return static::AWESOME_LIST;
}
}
class ConcreteTemplate extends AbstractTemplate {
public const AWESOME_LIST = ['harry','henk','john'];
public function someFunction(): void {
parent::someFunction();
}
}
$concreteTemplate = new ConcreteTemplate();
$concreteTemplate->someFunction();
Notice the static keyword in method getAwesomeList.
Let's change a bit now:
public function getAwesomeList(): array
{
return self::AWESOME_LIST;
}
The output of the var_dump at someFunction would be:
array (size=1)
0 => string '' (length=0)
The static keyword is used in a Singleton design pattern.
See link: https://refactoring.guru/design-patterns/singleton/php/example
The simplest example to show the difference.
Note, self::$c
class A
{
static $c = 7;
public static function getVal()
{
return self::$c;
}
}
class B extends A
{
static $c = 8;
}
B::getVal(); // 7
Late static binding, note static::$c
class A
{
static $c = 7;
public static function getVal()
{
return static::$c;
}
}
class B extends A
{
static $c = 8;
}
B::getVal(); // 8
Looking at it from a "why would I use this?" perspective, it's basically a way to change the context from which the static method is being interpreted/run.
With self, the context is the one where you defined the method originally. With static, it's the one you're calling it from.
For example:
abstract class Builder {
public static function build() {
return new static;
}
}
class Member extends Builder {
public function who_am_i() {
echo 'Member';
}
}
Member::build()->who_am_i();
Also, watch if you update static variables in child classes. I found this (somewhat) unexpected result where child B updates child C:
class A{
protected static $things;
}
class B extends A {
public static function things(){
static::$things[1] = 'Thing B';
return static::$things;
}
}
class C extends A{
public static function things(){
static::$things[2] = 'Thing C';
return static::$things;
}
}
print_r(C::things());
// Array (
// [2] => Thing C
// )
B::things();
print_r(C::things());
// Array (
// [2] => Thing C
// [1] => Thing B
// )
You can fix it by declaring the same variable in each child class, for example:
class C extends A{
protected static $things; // add this and B will not interfere!
public static function things(){
static::$things[2] = 'Thing C';
return static::$things;
}
}

Categories