Why does calling this method statically work? - php

class Duck {
public function quack() {
$this­->swim();
}
public function swim() {
echo 'I\'m swimming!';
}
}
class Plane {
public function fly() {
Duck::quack();
}
public function swim()
{
echo 'I can\'t swim! People are DROWNING!';
}
}
$plane = new Plane();
$plane-­>fly();
I got asked the above question and gave the answer that the output is an error illegally calling static method.
But it actually prints "I'm swimming!".
Could somebody please explain why this happens?

It works by default, but if you turn on E_STRICT you'll get
PHP Strict Standards: Non-static method Duck::quack() should not be called statically in...
PHP sees that you wanted swim() to be actually static and so it let's you simply call it.

Something to note with PHP 5.3 (and public methods):
CAN call public methods statically from anywhere INSIDE Object context (only if inside instantiated object)...even if not declared static
Duck::quack();
CANT call protected method in same scenario.
Duck::quack(); //error
protected function quack() { }
CANT call public properties (instance variables) statically from anywhere INSIDE Object context, unless declared static...
class Duck {
public $hello = 'hello there';
}
class Plane {
Duck::$hello; //error
}
CANT call public methods (or properties) statically from OUTSIDE object context..unless declared static
Duck::quack(); //error
Other languages use this type of engine flexibility, calling any public method statically as long as from inside Object context.
As mentioned (by #poitroae) it works like this by default, but if you turn on E_STRICT you'll get an error.
ALSO:
It is a known idiosyncrasy with PHP that you should'nt be allowed to call $this in this Context. The program should be under Class Context at this point (being called statically) but $this works which is akin to Object Context.
If this were a statically declared Method than calling $this would cause an instant fatal error.
Hope that helps

Related

Instance vs. static method. Calling it statically or dynamically

In PHP there is instance methods and static methods (just these two types)? Then we can call either of these statically or non-statically (is the name "dynamically"?)?
So we can:
Call an instance method statically;
Call an instance method non-statically;
Call a static method statically;
Call a static method non-statically (all four correct?)
How would the code for these four look? Are there any good websites explaining this? I am currently reading the following url:
http://php.net/manual/en/language.oop5.basic.php
...and I am not understanding this:
"$this is a reference to the calling object (usually the object to which the method belongs, but possibly another object, if the method is called statically from the context of a secondary object)."
How would the code look for calling a method statically from a secondary object? I mean, staticall calling vs. non-statical calling, what this is?
You are not supposed to call non static methods statically.
Some examples
class foo{
public static function bar(){
echo __METHOD__;
}
public function biz(){
echo __METHOD__;
}
}
Tests
//instance call
(new foo)->biz(); //echos foo::biz (don't worry about the :: here, its part of __METHOD__)
//static call, statically
foo::bar() // echos foo::bar
//call non-static statically
foo::biz() //in PHP7.1
<b>Deprecated</b>: Non-static method foo::biz() should not be called statically in <b>[...][...]</b> on line <b>18</b><br />
//call static non-statically
(new foo)->bar(); // echos foo::bar
The idea behind calling static non-statically is that its permissible to use static properties inside non static methods. For example:
class foo{
protected static $boo = "hello";
public static function bar(){
echo __METHOD__;
}
public function biz(){
echo __METHOD__;
echo self::$boo;
echo static::$boo; //late static binding
}
}
So this is fine, now the flip side is calling non-static methods inside of a static methods.
class foo{
protected $boo = "hello";
public static function bar(){
echo __METHOD__;
$this->boo; // this is a no no, because no instance exists and therefor $this does not work
}
public function biz(){
echo __METHOD__;
}
}
A few other things to point out
When calling static $this is not usable, it's assumed you will use $this in a non-static method, so calling it statically can cause issue.
When calling non static $this exists, and there is no problem making a static call, so calling static methods non statically is not an issue. ie. self and static is available no mater the context.
Static properties are shared with all instances of the class
Static properties accessed in parent cannot be changed by children (when using self)
Static properties accessed in parent can be changed by children (when using static, late static binding)
Now if you want exact answers:
Call an instance method statically;
you can but shouldn't because $this is not exists
Call an instance method non-statically;
this is normal
Call a static method statically;
this too is normal
Call a static method non-statically (all four correct?)
sure static is available no matter the scope
We can show this by example using the above class
class foo{
public static function bar(){
echo __METHOD__;
}
public function biz(){
echo __METHOD__;
print_r($this);
}
}
//call non-static statically
foo::biz();
Result (PHP7+)
<br />
<b>Deprecated</b>: Non-static method foo::biz() should not be called statically in <b>[...][...]</b> on line <b>15</b><br />
foo::biz //output of __METHOD__
<br />
<b>Fatal error</b>: Uncaught Error: Using $this when not in object context in [...][...]:11
Stack trace:
#0 [...][...](15): foo::biz()
#1 {main}
thrown in <b>[...][...]</b> on line <b>11</b><br />
AS you can see we get a Fatal error when trying to access $this
Result (PHP5 something)
<br />
<b>Strict Standards</b>: Non-static method foo::biz() should not be called statically in <b>[...][...]</b> on line <b>16</b><br />
foo::biz<br />
<b>Notice</b>: Undefined variable: this in <b>[...][...]</b> on line <b>11</b><br />
Now we don't get the Fatal error in pr PHP7 (something), and at first glance this may seem ok. Like its saying it's fine to run this way. However if you look closer Undefined variable: this this is actually worse then the Fatal error, because now you class can produce unexpected results.
If we had called this normal:
(new foo)->biz();
Result
foo::biz //output of __METHOD__
foo Object //output of $this
(
)
So I want to give you one quick example on self vs static, it can be really confusing.
class foo{
protected static $test = 'true';
public function boo(){
echo self::$test."\n";
echo static::$test."\n";
}
}
class bar extends foo{
protected static $test = 'false';
public function biz(){
echo self::$test."\n";
echo static::$test."\n";
}
}
$B = new bar;
$B->boo();
echo "--------------\n";
$B->biz();
Result
-------------- defined in parent ----
true //call boo() self
false //call boo() static
-------------- defined in child ----
false //call biz() self
false //call biz() static
When you use static it's called late static binding. What this means is that the static value is bound late. So what doe that really mean? It means the value is resolved at run time, not when the class is parsed by PHP.
bar is a child of foo.
We instantiate the child foo, all our calls go through foo.
the method boo only exists in the parent, ie. it's not overwritten by a child method.
foo's value is 'true'
bar's value is 'false'
For the fist one, we get the value of foo because we are using self, so it only knows about itself.
For the second one, we get the value of bar because we are using static, it's bound late and can use the child's value which is set in it's declaration of the property $test. So even though the parent doesn't know anything about the child (typical) it can use it's value because it's resolved at run time.
for the third one, we get the value of bar because it knows about itself, and the method is defined in itself. foo knows nothing about this method even if it did it would be overwritten by the deceleration of it in the child.
for the fourth one, again we get the value of bar this is because even with late static binding we pull the same data, the value of bar because bar is the class we instantiated, so at run time the value defined in's property is the value.
So in the last 2 the value is the same, it's because self and static resolve the same information regardless of when they are called.
This can be very confusing so hopefully it makes sense. Also as I have shown don't be afraid to make some simple classes like this and test the values you get. That's how I learned.
UPDATE
You mentioned using static calls was considered bad.
I think most of that comes from Dependency issues. This is tight coupling between the name of the class and your code. When using an instance, you assign it to variable and use the name 1 time when calling new. When calling static you use the class name every time. The problem this causes is if you decide to rename the class. With instance calls you only need to replace the name where you call new, with static you have to replace it everywhere.
For example consider this.
$foo = new foo;
$foo->one();
$foo->two();
//say you inject this into another class
$foo->three();
And compare it to this.
foo::one();
foo::two();
//say you inject this into another class
foo::three();
Now say you change the class name. For the first one you have to replace it in one place. For the second one you have to replace it evey where you used it. You can get around this somewhat by using a string variable.
$class = 'foo';
$class::one();
$class::two();
//say you inject this into another class
$class::three();
But with this you can get into a lot of trouble too, because most IDE's wont be able to resolve the class and do auto-completion.
Also if you do type hinting on inputs to other classes
class other{
public method inject(foo $foo){}
}
This doesn't work very well on static classes, because you are passing in a string then (the class name).
Namespaces can be an issue. With instantiation, you only need to put the use statement in the file you instantiate the class in. With static, you have to put it everywhere, or include it in every call.
\mystuff\foo::bar();
$foo = '\\mystuff\\foo';
$foo::bar();
I am sure there are other reasons, but these are the main ones for me.
Let's look the following code:
<?php
class A
{
public $property = "property A";
public function testA()
{
echo "class A ";
echo $this->property;
}
}
class B
{
public $property = "property B";
public function testB()
{
A::testA();
}
}
$b = new B;
$b->testB();
It will display class A property B
You are accessing a property from B, in A class, with $this.
This will not work on PHP 7+, and you will get the following warning on PHP 5.6:
WARNING Non-static method A::testA() should not be called statically, assuming $this from incompatible context on line number 16
It "works", but you are not supposed to call non-static methods from static context.

PHP Late Static Binding referencing calling class

I have a static function being called that is giving a strange error. Here is an example of the php code:
class foo {
public $stat;
public function __construct() {
$this->stat = stat::isValid('two');
}
}
class stat {
protected static $invalidNumbers = array('one', 'two');
function isValid($number) {
return in_array($number, static::$invalidNumbers);
}
}
$foo = new foo();
var_dump($foo->stat);
This code results in the following error:
Fatal error: Access to undeclared static property: foo::$invalidNumbers
However changing static:: to self:: makes the code behave as expected. I was under the impression that in this context using static:: should work.
Why does this error occur using static?
You begin by making a method call in a static context:
stat::isValid('two');
When you do this, PHP "remembers" the context from within which isValid was called specifically so that it can resolve what to bind to when it sees something like static:: inside the method body, determine if some property you are trying to access is visible, and in general be able to implement some OO-related language features.
The actual method isValid is not static, but PHP still allows you to call it using the static method syntax (it does give an E_STRICT warning about that). However, this has the side effect that isValid itself does not participate in modifying the curent calling context for (late) static bindings.
The result: when PHP sees static::$invalidNumbers, it still thinks you are halfway through making a static method call from within the foo class! Once you realize this, it is obvious why static:: resolves to foo:: and it ends up looking for the property at the wrong place.
If you correctly declare isValid as static
static function isValid($number) {
return in_array($number, static::$invalidNumbers);
}
then upon calling the method PHP does update its context internally and manages to bind to the intended member.
You are trying to call the method stat::isValid() statically but have not declared it static. Change the stat class to:
class stat {
protected static $invalidNumbers = array('one', 'two');
// needs to be declared static
static function isValid($number) {
return in_array($number, static::$invalidNumbers);
}
}
Note that, if you add
| E_STRICT
to your error_reporting in php.ini you would see a message like:
Strict standards: Non-static method stat::isValid() should not be called statically, assuming $this from incompatible context in ...
Declare static method properly
Replace
function isValid($number) {
With
public static function isValid($number) {
^--- here

The mysterious behaviour of __callStatic method

SO question Weird behaviour with triggering __callStatic() from non-static method is great because it explains the weird behaviour with the __callStatic not being called from within the class itself (Note that I don't see this behaviour in 5.3.3 but in 5.3.8 and 5.3.12). It seems that the __callStatic can only be invoked from outside the class. That's now a fact. But what do I do if I really want the __callStatic to be called from within my class? What syntax should I use to get over the issue?
It does not have to be from outside the class, just not from object context (i.e. where $this is an instance of the class). So you can wrap this call in a static method, for example:
class TestCallStatic
{
public function __call($func, $args)
{
echo "__call($func)";
}
public static function __callStatic($func, $args)
{
echo "__callStatic($func)";
}
public function test()
{
self::_test();
}
protected static function _test()
{
self::i_am_static();
}
}
$test = new TestCallStatic();
$test->test();
Output:
__callStatic(i_am_static)
You could abstract the functionality to another method like Class::magicCall($method, $args) and call that from within __callStatic(). That way you can also access that functionality by simply calling Class::magicCall() directly.

static function in PHP

If I call public function using scope resolution operator, It is not giving any error.
class Parent_class
{
public function st_function()
{
echo "*************parent class************\n";
}
}
Parent_class:: st_function();
But in PHP documentation on php.net, it ig given that - Calling non-static methods statically generates an E_STRICT level warning. Also its given that - Static properties cannot be accessed through the object using the arrow operator ->
But its not giving any error. Can anyone explain?
class Parent_class
{
public static function st_function()
{
echo "*************parent class************\n";
}
}
Parent_class:: st_function();
$var = new Parent_class();
$var->st_function();
Static properties can not be accessed through the object, but not static methods.
From the doc.
Declaring class properties or methods as static makes them accessible
without needing an instantiation of the class. A property declared as
static can not be accessed with an instantiated class object (though
a static method can).
If you activate strict error reporting, you will see an error for calling a non-static method statically:
error_reporting(E_ALL | E_STRICT);
For the second part, where you call a static method non-statically, that will work because the paragraph in the manual talks about static properties, not methods. You cannot access Parent_class::static_property like Parent_class->static_property, if it had such a property.
Calling static methods of objects works fine, in that case the $var-> is just a convenience shorthand for Parent_class::.
Try this before your code:
error_reporting(E_ALL | E_STRICT);

PHP, OOP, Static

I am studying PHP,OOP and i am at Static,
At this php.net/static i didnt understand this sentence
Calling non-static methods statically generates an E_STRICT level warning.
I did understand it's Valid for methods only (not for Properties) by the sentence above,
but i didn't succeed to understand It practically,
I'm glad if anything could please show me code that explains the sentence above,
Wishing you a pleasant week.
class Foo
{
public static $my_static = 'foo';
public $my_non_static = 'bar';
public function staticValue() {
return self::$my_static;
}
public function nonStaticValue() {
return self::$my_non_static;
}
}
print Foo::$my_static . "\n"; // OK
print Foo::staticValue(). "\n"; // E_STRICT
print Foo::$my_non_static . "\n"; // Fatal
print Foo::nonStaticValue(). "\n"; // Fatal
print Foo::$my_static . "\n"; is OK - static property accessed statically.
print Foo::staticValue(). "\n"; gives E_STRICT - non-static method accessed statically, but not Fatal error, because this method doesn't access non-static properties.
Other two give Fatal error because non-static field cannot be accessed statically.
Here is an example of what they mean with the sentence you are asking about.
Consider the following class with one method (it is not static).
class Test
{
function method()
{
echo "Hello from method";
}
}
Test::method(); // attempt to statically call a non-static method
This is the output:
Strict Standards: Non-static method Test::method() should not be
called statically in /obj.php on line 12
Hello from method
As you can see, it did execute the method when called static even though it is not a static method, however a strict error message was displayed.
If the method method() referenced the keyword $this, then you would encounter a fatal error because $this does not exist in the context of a static method call. So while it is technically possible to call a non-static class method statically, it should not be done.
EDIT:
The reason you are even allowed to call a non-static class member statically is because the static keyword did not exist in PHP4 in the context of class methods so if you were designing a static class or method in PHP4, there was no keyword to indicate it, you would simply call it in the static fashion. Now PHP5 emits the warning if the method is called statically but doesn't have the static keyword in the declaration.
It's because even if you can call non-static methods statically, you shouldn't and it will be logged.
class Foo {
function bar(){
print "you should not do that";
}
}
Foo::bar(); would actually works, but you will get a E_STRICT warning because you can do that, but you shouln't.
If a method is non-static, it means that it belongs to an instance of a class. For example, if we have a class Car with a method called getDamage() (which computes how much damaged the car is), then you should not call this method in a static way.
You should only create an instance of the Car class and call getDamage() on that instance. This makes sense because a particular car can be damaged for 25% while another car can be damaged for 70%.
But calling getDamage() in a static way makes no sense: a static method does not belong to a particular instance of the class but to the class itself. And a Car class has no useful way of giving a result for getDamage(). You could still compute a value (perhaps 0) but it does not make sense.

Categories