PHP 5.3 strange behaviour on static:: late binding - php

<?php
class baseModel
{
public static function show($className=__CLASS__)
{
print_r($className);
}
public function test()
{
static::show();
}
}
class AModel extends baseModel
{
public static function show($className=__CLASS__)
{
print_r($className);
}
}
class Controller
{
public function actionTest()
{
baseModel::test();
AModel::test();
}
}
$c = new Controller;
$c->actionTest();
?>
Expected output:
baseModelAModel
Actual output:
Fatal error: Call to undefined method Controller::show() in /var/www/dashboard/test.php on line 12
Why did PHP try to find Controller::show() rather than AModel::show?

static keyword refers to context, not the class the method was defined in. So, when you call A::test from context of C, static refers to C.

As it writes in php manual
In non-static contexts, the called class will be the class of the object instance. Since $this-> will try to call private methods from the same scope, using static:: may give different results. Another difference is that static:: can only refer to static properties.
This means that in context of object $c (class Controller) making a non-static call ($c->t()) late binding static:: keyword in method baseModel::test() references class of object reference $this which is Controller and not called class, while if calling static:
Controller::test();
Context of static:: is called class.
I would however advise you not to use static calls unless methods are explicitly defined as static:
class baseModel
{
public static function show($className=__CLASS__)
{
print_r($className);
}
public static function test()
// must be defined as static or context of static:: may change to Controller instead of actual class being called!
{
static::show();
}
}
This code works because if defining explicitly baseModel::test() as being static context of static:: will always be static.

Related

Determine the name of the calling class (parent or child) in parent class method

Looking for a clean way to determine the class (in this case, either parent or child class) of the method that calls a method in the parent class.
I thought late static binding could handle this, but seems like that only really works for calling a static method directly, and not from within an instantiated object's method.
Consider the following:
abstract class ParentClass {
public function parentMethod() {
self::_log("parent.non.static");
}
public static function parentStatic() {
self::_log("parent.static");
}
public static function getClassName() {
return __CLASS__;
}
protected static function _log($key) {
$prefix = 'graphite.key.prefix';
$class = static::getClassName(); // gets the object's class, not calling class
$g_key = "{$prefix}.{$class}.{$key}";
echo "{$g_key} \n";
// Graphite::increment($g_key);
}
}
class ChildClass extends ParentClass {
public function childMethod() {
self::_log("child.non.static");
}
public static function childStatic() {
self::_log("child.static");
}
public static function getClassName() {
return __CLASS__;
}
}
$obj = new ChildClass;
$obj->childMethod(); // graphite.key.prefix.ChildClass.child.non.static
$obj->parentMethod(); // graphite.key.prefix.ChildClass.parent.non.static
ParentClass::parentStatic(); // graphite.key.prefix.ParentClass.parent.static
ChildClass::childStatic(); // graphite.key.prefix.ChildClass.child.static
Looking for a clean way to get the class that calls the _log() method without having to pass it in as a parameter. Doesn't have to be static at all, but I was playing around with the late static binding, because I thought that would work, but it just gets the name of the instantiated object, not the child/parent class of the method that calls the _log() method :-/
Edit:
Just to be clear, I'm after getting the class name of the method that called _log() from within the instantiated object (like parentMethod() and childMethod()) Don't care if _log() is static or not. If that makes it easier, fine. But the static ParentClass::parentStatic() and ChildClass::childStatic() were just to show late static bindings and what I figured might work, but not from calling within an instantiated object
http://php.net/manual/en/function.get-called-class.php
class One {
public static function test() {
echo get_called_class() . PHP_EOL;
}
}
class Two extends One {}
One::test();
Two::test();
Output:
One
Two
Also, according to the top comment in the docs static::class also works as of PHP 5.5.
get_class will get the class name of a class instance. This can also be called on $this within a class. If you have a class that extends/implements another, $this will refer the the instantiated class, meaning the child class.
Another option is to use debug_backtrace to get the stack of functions that lead up to where you currently are. You can parse the returned array to get whatever you need including line numbers, classes, functions, methods, whatever.

different between static:: and $this-> and which syntax i should use?

I have some code:
class a {
public static function getCl() {
echo __CLASS__;
}
public function test() {
static::getCl();
}
}
class b extends a {
public static function getCl() {
echo __CLASS__;
}
}
$testClass = new b();
$testClass->test();
and this result : b. Then i try this:
class a {
public static function getCl() {
echo __CLASS__;
}
public function test() {
$this->getCl();
}
}
class b extends a {
public static function getCl() {
echo __CLASS__;
}
}
$testClass = new b();
$testClass->test();
this result is still b. I already know the different between static:: and self:: but can someone show me what is the different between static:: and $this-> in my code. Which one should i use?
Your context will produce the same result.
Here is simply description about both.
static:- refers late static binding 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.
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:
While 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 child class from parent class method. It was decided not to introduce a new keyword but rather use static that was already reserved.
$this:- refers current object.
Once inside an object's function, you have complete access to its variables, but to set them you need to be more specific than just using the variable name you want to work with. To properly specify you want to work with a local variable, you need to use the special $this variable, which PHP always sets to point to the object you are currently working with.

Difficulty understanding how to declare a parent class's function in an extended class?

class Bar{
public function test(){
$this->testPublic();
$this->testPrivate();
}
public function testPublic(){
echo "Bar::testPublic\n";
}
private function testPrivate(){
echo "Bar::testPrivate\n";
}
}
class Foo extends Bar{
public function testPublic(){
echo "Foo::testPublic\n";
}
private function testPrivate(){
echo "Foo::testPrivate\n";
}
}
$myFoo = new Foo();
$myFoo->test();
//Foo::testPublic
//Bar::testPrivate
I'm having a lot of trouble understanding this output. Would someone be able to give me a clear succinct explanation of what is going on? I'm learning OOP and wanted to know how to use extensions to override the parent class functions.
The test() method calls 2 methods:
testPublic - it's a public one, so it was overriden in the Foo. So the Foo::testPublic is called
testPrivate - it's a private one, so it's only visible for each class itself. For the caller method (it's Bar) - it's a Bar::testPrivate
So - if the method is public or protected - it can be overriden and called from the ancestor/child; if it's private - it cannot.
The $this references the current object. So when you do the following.
$this->testPublic();
It will call testPublic() for the top most class that implements that function.
If you want to only call the parent class, then there is the parent keyword.
parent::testPublic();
That will call testPublic() on the class below the current object.
Becare full not to confuse the -> operator with the :: operator.
The :: operator references the class definition of an object, where as -> references the instance of an object.
self::testPublic();
$foo::testPublic();
That references a static function called testPublic(), and static methods are defined at the class level.
$foo->testPublic();
$this->testPublic();
That references a function as part of the instance of an object, and there is a vtable used to look up which object instance level should be called.

call a static method inside a class?

how do i call a static method from another method inside the same class?
$this->staticMethod();
or
$this::staticMethod();
self::staticMethod();
More information about the Static keyword.
Let's assume this is your class:
class Test
{
private $baz = 1;
public function foo() { ... }
public function bar()
{
printf("baz = %d\n", $this->baz);
}
public static function staticMethod() { echo "static method\n"; }
}
From within the foo() method, let's look at the different options:
$this->staticMethod();
So that calls staticMethod() as an instance method, right? It does not. This is because the method is declared as public static the interpreter will call it as a static method, so it will work as expected. It could be argued that doing so makes it less obvious from the code that a static method call is taking place.
$this::staticMethod();
Since PHP 5.3 you can use $var::method() to mean <class-of-$var>::; this is quite convenient, though the above use-case is still quite unconventional. So that brings us to the most common way of calling a static method:
self::staticMethod();
Now, before you start thinking that the :: is the static call operator, let me give you another example:
self::bar();
This will print baz = 1, which means that $this->bar() and self::bar() do exactly the same thing; that's because :: is just a scope resolution operator. It's there to make parent::, self:: and static:: work and give you access to static variables; how a method is called depends on its signature and how the caller was called.
To see all of this in action, see this 3v4l.org output.
This is a very late response, but adds some detail on the previous answers
When it comes to calling static methods in PHP from another static method on the same class, it is important to differentiate between self and the class name.
Take for instance this code:
class static_test_class {
public static function test() {
echo "Original class\n";
}
public static function run($use_self) {
if($use_self) {
self::test();
} else {
$class = get_called_class();
$class::test();
}
}
}
class extended_static_test_class extends static_test_class {
public static function test() {
echo "Extended class\n";
}
}
extended_static_test_class::run(true);
extended_static_test_class::run(false);
The output of this code is:
Original class
Extended class
This is because self refers to the class the code is in, rather than the class of the code it is being called from.
If you want to use a method defined on a class which inherits the original class, you need to use something like:
$class = get_called_class();
$class::function_name();
In the later PHP version self::staticMethod(); also will not work. It will throw the strict standard error.
In this case, we can create object of same class and call by object
here is the example
class Foo {
public function fun1() {
echo 'non-static';
}
public static function fun2() {
echo (new self)->fun1();
}
}
call a static method inside a class
className::staticFunctionName
example
ClassName::staticMethod();

php static function

I have a question regarding static function in php.
let's assume that I have a class
class test {
public function sayHi() {
echo 'hi';
}
}
if I do test::sayHi(); it works without a problem.
class test {
public static function sayHi() {
echo 'hi';
}
}
test::sayHi(); works as well.
What are the differences between first class and second class?
What is special about a static function?
In the first class, sayHi() is actually an instance method which you are calling as a static method and you get away with it because sayHi() never refers to $this.
Static functions are associated with the class, not an instance of the class. As such, $this is not available from a static context ($this isn't pointing to any object).
Simply, static functions function independently of the class where they belong.
$this means, this is an object of this class. It does not apply to static functions.
class test {
public function sayHi($hi = "Hi") {
$this->hi = $hi;
return $this->hi;
}
}
class test1 {
public static function sayHi($hi) {
$hi = "Hi";
return $hi;
}
}
// Test
$mytest = new test();
print $mytest->sayHi('hello'); // returns 'hello'
print test1::sayHi('hello'); // returns 'Hi'
Entire difference is, you don't get $this supplied inside the static function. If you try to use $this, you'll get a Fatal error: Using $this when not in object context.
Well, okay, one other difference: an E_STRICT warning is generated by your first example.
Calling non-static methods statically generates an E_STRICT level warning.
In a nutshell, you don't have the object as $this in the second case, as
the static method is a function/method of the class not the object instance.
After trying examples (PHP 5.3.5), I found that in both cases of defining functions you can't use $this operator to work on class functions. So I couldn't find a difference in them yet. :(

Categories