PHP: get_called_class() returns unexpected value - php

Using PHP 5.3+ and having something equal to the following I get the output of 'C' instead of 'B':
class A
{
public static function doSomething()
{
echo get_called_class();
}
}
class B extends A
{
public static function doMore()
{
self::doSomething();
}
}
class C extends B {}
C::doMore();
If I had used static::doSomething() that would be the expected result, but when using self::doSomething() I expect this method to get called in the scope of B because it's where the 'self' is defined and not the late static binding.
How is that explained and how do I get 'B' in the doSomething() method?
Thanks in advance, JS

The issue here is late static binding. The get_called_class() function will use late static binding to return the class name, __CLASS__ will use late static binding if called using static::, but not when used with $this-> or self::. I don't know of a way to get it to return B short of having the echo within B instead of A. It sounds like this would be an ideal use of traits if you were using PHP 5.4.
Example:
class A
{
public static function doSomething()
{
echo __CLASS__;
}
}
class B extends A
{
public static function doMore()
{
self::doSomething();
}
}
class C extends B {}
C::doMore();
This returns A instead of C.

Override the method doSomething, to get B
class C extends B
{
public static function doMore()
{
B::doMore();
}
}
Tested

Related

Does parent:: automatically determine class and object invoke context?

In first case we called function in object context. In second case we have class context.
Does parent:: work like this and self simultaneously depending on the context?
class par_parent{
private $var='value1';
private static $val='value2';
public function call(){
var_dump('Object '.$this->var);
}
public static function staticCall(){
var_dump('Static '.self::$val);
}
}
class par_child extends par_parent{
public function callObj(){
parent::call();
}
public static function callStatic(){
parent::staticCall();
}
}
$obj=new par_child();
$obj->callObj();
**//string 'Object value1' (length=13)**
par_child::callStatic();
**//string 'Static value2' (length=13)**
The parent:: is binded like the self:: keyword, always sees the context where it have been defined code wise, not from where it's called, so in essence it works like the self:: keyword. If you need it to work like the $this use late static binding provieded static::. Consider this example:
class A {
protected static $v = 'a';
public static function staticsay() {
print static::$v;
}
}
class B extends A {
protected static $v = 'b';
public static function say(){
print parent::$v;
}
}
class C extends B {
protected static $v = 'c';
public static function selfsay(){
print parent::$v;
}
}
C::say(); // prints 'a'
C::selfsay(); // prints 'b'
C::staticsay(); // prints 'c'
Here we call the say() method on C it comes from the class B so it's parent:: means A and the A::$v is 'a' so it prints that.
While the parent:: in C points to the class B and it sees it's $v as 'b'.
With php 5.3 comes late static binding and the static:: keyword that lets you access the static variables and methods in baseclasses static methods so the A::staticsay will see the $v from the class C.

Dynamic binding in static method php

class A
{
static function get_name_derived_class()
{
//This function must return the name of the real class
//Is it possible without insert a methon in B class?
{
}
class B extends A
{
}
B::test()
I'd like to have a static methon in base class which returns the name of real (derived) class, without insert a specific method in it. is it possible?
thanx
<?php
class A
{
static function test()
{
return get_called_class();
}
}
class B extends A
{
}
echo B::test();
Requires PHP >= 5.3.0. See PHP's manual entry on Late Static Bindings

PHP Can static:: replace self::?

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

PHP faked multiple inheritance - having object attributes set in fake parent class available in extended class

I have used faking of multiple inheritance as given in Can I extend a class using more than 1 class in PHP?
Notice that class A actually extends class B and faking is done for extending from class C.
It was working fine until I needed an attribute set in a function of class C to be available in class A. Consider a little edited version of that code where I call a function of class C from inside a function of class A :-
//Class A
class A extends B
{
private $c;
public function __construct()
{
$this->c = new C;
}
// fake "extends C" using magic function
public function __call($method, $args)
{
return call_user_func_array(array($this->c, $method), $args);
}
//calling a function of class C from inside a function of class A
public function method_from_a($s) {
$this->method_from_c($s);
echo $this->param; //Does not work
}
//calling a function of class B from inside a function of class A
public function another_method_from_a($s) {
$this->method_from_b($s);
echo $this->another_param; //Works
}
}
//Class C
class C {
public function method_from_c($s) {
$this->param = "test";
}
}
//Class B
class B {
public function method_from_b($s) {
$this->another_param = "test";
}
}
$a = new A;
$a->method_from_a("def");
$a->another_method_from_a("def");
So, an attribute set in a function of class C is not available afterwards in class A but if set in class B, it is available in class A. What adjustment am I missing so as to make setting of attributes in the fake parent class work like real? An attribute set in fake parent's function should be available in all the classes of the hierarchy like in normal case.
Thanks
Solved
I added the magic function __get() in class A and it worked.
public function __get($name)
{
return $this->c->$name;
}
That will never work, because 'param' is not a property of A: it is in c, which is a property of A.
What you need to do is define the magic methods such as __set and __get, which parallel __call for properties.

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