PHP Can static:: replace self::? - php

I am a little confused with this matter. I am designing an ORM class that tries to behave very similarly to ActiveRecord in ruby on rails, but that's beside the point.
What I'm trying to say is that my class makes extensive use of static attribute inheritance, specially for database and table handling. My question is, should I use self:: at all?

You have to ask yourself: "Am I targeting the problem with the adequated approach?"
self:: and static:: do two different things. For instance self:: or __CLASS__ are references to the current class, so defined in certain scope it will NOT suffice the need of static calling on forward.
What will happen on inheritance?
class A {
public static function className(){
echo __CLASS__;
}
public static function test(){
self::className();
}
}
class B extends A{
public static function className(){
echo __CLASS__;
}
}
B::test();
This will print
A
In the other hand with static:: It has the expected behaviour
class A {
public static function className(){
echo __CLASS__;
}
public static function test(){
static::className();
}
}
class B extends A{
public static function className(){
echo __CLASS__;
}
}
B::test();
This will print
B
That is called late static binding in PHP 5.3.0. It solves the limitation of calling the class that was referenced at runtime.
With that in mind I think you can now see and solve the problem adequately. If you are inheriting several static members and need access to the parent and child members self:: will not suffice.

try to use the code bellow to see the difference between self and static:
<?php
class Parent_{
protected static $x = "parent";
public static function makeTest(){
echo "self => ".self::$x."<br>";
echo "static => ".static::$x;
}
}
class Child_ extends Parent_{
protected static $x = "child";
}
echo "<h4>using the Parent_ class</h4>";
Parent_::makeTest();
echo "<br><h4>using the Child_ class</h4>";
Child_::makeTest();
?>
and you get this result:
using the Parent_ class
self => parent
static => parent
using the Child_ class
self => parent
static => child

Related

PHP: is it possible to call a static class method from another static class?

Consider a static class (private constructor, only static methods & variables).
Now the rough class definition would look like this:
class A{
private function __construct(){}
public static test(){};
}
class B{
private function __construct(){}
}
Is it somehow possible to call something like B::A::test() ?
Or maybe through a variable? Something like B::$A::test() ?
I guess it is possible by some general call catching, but I can't figure it out...
IMPORTANT: Also, I want to call ANY other static class from B, not just from the A class...
EDIT2: What I want to achieve is to call static class through another static class, if possible... very similar to calling a method from object variable - but static class (obviously) is not ment to be instantiated.
EDIT3: Also possible solution is to call it as B::CLASSNAME_METHOD_NAME and catch it by __callStatic but I would rather do B::CLASSNAME::METHOD_NAME ...
Another possible solution:
If you don't want to create whole singleton, this could be solution - creating a partial singleton - some kind of singleton-hepler, altough using -> to call a static method could be confusing!
class AA{
private function __construct(){}
private static $instance;
public function getInstance(){ return empty(self::$instance)?(new self()):self::$instance; }
public function __call($method_name, $args) {
return AA::$method_name($args);
}
public static function test($a, $b){
echo "TEST: A:".$a." B:".$b;
}
}
class B{
private function __construct(){}
public static function A(){
return AA::getInstance();
}
}
B::A()->test("one", "two");
You would have to use this syntax:
class B {
const A = 'A';
}
$class = B::A;
$class::test()
This is essentially just the syntax for calling a static method on a variable class name. There's no nicer shortcut for it.
Note that I don't think such a pattern makes a lot of sense, your class design is too static at this point. You should be instantiating your classes and call $b->a->test(), which gives you more flexibility in your application design. Realistically B::A is hardcoded, it's not going to be anything other than 'A', so you may as well write A::test() directly.
If instead of a const you'd use a public static property which may vary at runtime, you now introduce global state into your app, which is also undesirable.
calling static function of a class from a static function of an another class
class A{
private function __construct(){}
public static function test()
{
echo 'from class A';
}
}
class B{
private function __construct(){}
public static function test()
{
return A::test();
}
}
A::test(); //outputs 'from class A'
B::test(); //outputs 'from class A'

Right way to instantiate class in PHP

I am trying to create a method inside class, that will instantiate class that is currently in. But I would also need that from this method to work correctly in all extended classes. As I have learned from this thread, it's not good to use self keyword for this task. So obvious choice would be using static keyword.
But, I've come across different method that also works.
Example:
class SimpleClass
{
private $arg;
public function __construct( $arg ){
$this->arg = $arg;
}
public function getArg(){return $this->arg;}
public function setArg($arg){$this->arg = $arg;}
public function staticInstance()
{
return new static( $this->arg );
}
public function thisInstance()
{
return new $this( $this->arg );
}
public function selfInstance()
{
return new self( $this->arg );
}
}
class ExtendedClass extends SimpleClass
{
}
$c1 = 'SimpleClass';
$c2 = 'ExtendedClass';
$inst1 = new $c1('simple');
$inst2 = new $c2('extended');
$static_instance_1 = $inst1->staticInstance();
$this_instance_1 = $inst1->thisInstance();
$self_instance_1 = $inst1->selfInstance();
$static_instance_2 = $inst2->staticInstance();
$this_instance_2 = $inst2->thisInstance();
$self_instance_2 = $inst2->selfInstance();
echo "SimpleClass Instances\n";
echo get_class($static_instance_1);
echo get_class($this_instance_1);
echo get_class($self_instance_1);
echo "ExtendedClass Instances\n";
echo get_class($static_instance_2);
echo get_class($this_instance_2);
echo get_class($self_instance_2);
As I can see from this example, both staticInstance and thisInstance produce "correct" results. Or do they?
Can someone explain difference between these two methods and which one is "correct" one.
php.net says:
As of PHP 5.3.0, PHP implements a feature called late static bindings which can be used to reference the called class in a context of static inheritance.
More precisely, 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.
This feature was named "late static bindings" with an internal perspective in mind. "Late binding" comes from the fact that static:: will not be resolved using the class where the method is defined but it will rather be computed using runtime information. It was also called a "static binding" as it can be used for (but is not limited to) static method calls.
Limitations of self:
Static references to the current class like self:: or CLASS are resolved using the class in which the function belongs, as in where it was defined:
<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
self::who();
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
?>
The above example will output: A
Late Static Bindings' usage:
Late static bindings tries to solve that limitation by introducing a keyword that references the class that was initially called at runtime. Basically, a keyword that would allow you to reference B from test() in the previous example. It was decided not to introduce a new keyword but rather use static that was already reserved.
<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
static::who(); // Here comes Late Static Bindings
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
?>
The above example will output: B
$this keyword refers to current object and you cannot use it in static methods. When you say return $this it means that some method returns the same object on which it was invoked.
So the correct way would be using static keyword because if you say return new static() it refers to the class the method is currently in.

Getting class constant inside class

What's the difference between self::CONSTANT_NAME and static::CONSTANT_NAME?
Is calling constant via static:: only 5.3 feature?
When you use static::NAME it's a feature called late static binding (or LSB). More information about this feature is at the php.net documentation page of LSB: http://nl2.php.net/manual/en/language.oop5.late-static-bindings.php
An example is this use case:
<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
self::who();
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
?>
This outputs A, which is not always desirable. Now replacing self with static creates this:
<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
static::who(); // Here comes Late Static Bindings
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
?>
And, as you might expect, it ouputs "B"
The difference is pretty much what late static bindings are all about.
Short explanation:
self:: will refer to the class type inside which the code using self:: is written.
static:: will refer to the class type of the actual object that on which the code using static:: is being executed.
This means that there's only a difference if we are talking about classes in the same inheritance hierarchy.

Extending PHP static classes

I've been struggling in this area for days now, and I have reached a conclusion, but since the conclusion was not what I was looking for, before I give up, I'll try to see what other people say. Faith dies last...
Let's say we have a superclass (called "Super") and a subclass (called "Sub").
class Super {
protected static $title = 'super';
public static function get_class_name()
{
echo __CLASS__;
}
public static function get_title()
{
echo self::$title;
}
}
class Sub extends Super {
protected static $title = 'sub';
}
Now, you would probably expect since Sub extends Super, that Sub would now inherit all of Super's methods, however, it seems to only receive references to the Sub's methods.
I say this because if I call:
Sub::get_class_name();
the output is "Super", and not "Sub".
And if I call:
Sub::get_title();
again, the output is "super", and I even have the $title declared in Sub.
So this means that when I call an inherited static function, the function's scope will be the super class, not the one called upon (even if you print the backtrace, it will show that the call was made on the superclass!!!), and in order to obtain the scope as the subclass that the call is being made upon, I need to redeclare that method inside that subclass. Well this kind of defeats the purpose of extending classes, don't it?
So my question is, can I ever extend a static class, call one of the inherited methods and have the subclass's scope? or at least to be able to identify it's classname?
And if not, why would I ever want to extend static classes?
Thanks!
Again, this is not possible prior to PHP 5.3.0.
Late Static Binding was introduced in PHP 5.3.0 and allows you to do exactly what you want via the static keyword.
class Super {
protected static $title = 'super';
public static function get_class_name()
{
echo __CLASS__;
}
public static function get_title()
{
echo static::$title;
}
}
class Sub extends Super {
protected static $title = 'sub';
}
get_class_name() will still return Super though has __CLASS__ always returns the current class the method being run is declared in (kind of like __FILE__ which always returns the current file no matter if you included it or not).
For that you don't have any choice but to re-declare the function in the Sub class.
class Super {
protected static $title = 'super';
public static function get_class_name()
{
echo __CLASS__;
}
public static function get_title()
{
echo static::$title;
}
}
class Sub extends Super {
protected static $title = 'sub';
public static function get_class_name()
{
echo __CLASS__;
}
}
You can used get_called_class() to get the class name of the class you are calling, even if it is static. You don't have to declare it anywhere.
From Andrew's Example:
class Super {
public static function get_class1_name()
{
echo __CLASS__;
}
public static function get_title()
{
echo get_called_class();
}
}
class Sub extends Super {
public static function get_class2_name()
{
echo __CLASS__;
}
}
Sub::get_title(); // Echos Sub.
Sub::get_class1_Name(); // echos super
Sub::get_class2_Name(); // echos sub
Therefore you don't have to declare any variables.
Fortunately, I'm doing something for me, so I said, screw it, I'm using PHP5.3. But even so, I don't like that I have to redeclare "get _class _name" in every class, maybe I'm extending like 10 classes. So I came up with this solution:
class Super {
protected static $classname = __CLASS__;
public static function get_classname($name)
{
static::$classname = $name;
}
public static function get_classname()
{
return static::$classname;
}
}
class Sub1 extends Super { }
class Sub2 extends Super { }
class Sub3 extends Super { }
$classes = get_declared_classes();
foreach($classes as $k => $v)
{
if (is_subclass_of($v, 'Super'))
{
$v::set_classname($v);
}
}
echo Sub1::get_classname(); // Sub1
echo Sub2::get_classname(); // Sub2
echo Sub3::get_classname(); // Sub3
It might seem a little dirty, but I don't think it's that bad. With this done, you can finally extend static methods without having to re-declare methods.

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