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.
Related
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.
Why is the 'self'-call to a non-satic method in this example working?
class A{
protected function aNonStaticMethod(){
return __class__;
}
public function aEcho(){
echo self::aNonStaticMethod();
}
}
Thanks for explanation.
In your simple example $this and self is interchangable. But be aware of the different method resolving when dealing with inheritance (i added static for completeness):
class A {
protected function aNonStaticMethod(){
return __class__;
}
public function selfEcho(){
echo self::aNonStaticMethod();
}
public function staticEcho(){
echo static::aNonStaticMethod();
}
public function thisEcho(){
echo $this->aNonStaticMethod();
}
}
class B extends A {
protected function aNonStaticMethod(){
return __class__;
}
}
$b = new B();
$b->selfEcho(); // A
$b->staticEcho(); // B
$b->thisEcho(); // B
Calling non-static method statically
Theoretically it should not work, but as this comment says:
There was no static keyword in php4 but php4 did allow for static
calls. To maintain backwards compatibility this was left in when the
static keyword was added in php5.
This comment is supported by this official php.net wiki:
This is already deprecated if the call occurs from an instance method.
Not annotating methods as static is an obsolete PHP4-ism.
You really should not call non-static method statically - it does not make sense (if there is a static keyword).
Avoid calling non-static methods statically completely!
...because a) it is a bad approach and b) the PHP docs say:
Caution
In PHP 5, calling non-static methods statically generates an E_STRICT level warning.
AND
Warning
In PHP 7, calling non-static methods statically is deprecated, and will generate an E_DEPRECATED warning. Support for calling non-static methods statically may be removed in the future.
Using :: operator for non-static calls - may be a good approach!
As #Kontrollfreak pointed out and as this docs say the :: operator is not limited to static calls:
the double colon, is a token that allows access to static, constant,
and overridden properties or methods of a class
So it is OK if you reference this way a method or properties from a parent class - which is not limited to a direct parent.
EDIT: do not mistake this for Fascade etc. software patterns!
During writing this answer I forgot to mention that there might be cases, when the call is static, but internally it is calling dynamic method - for more info see patterns like Facade or Singleton.
However do NOT mistake these with issue described above! (issue above is about using direct static call on dynamic thing that should be called dynamically, these patterns are about calling static methods statically, which then may dynamically invoke something dynamic (internally)).
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
http://codepad.viper-7.com/I0Zqoi
I don't understand what's wrong with this or how to fix it or why. Can someone who knows a little about programming please explain what's happening behind the scenes, like on the interpreter level? Also, how can I fix my problem, and why do I need to write my code in the way of the correction? Can you tell me, in human language, what is wrong with this and how to make it better? I guess my book isn't explaining well, and the code inside of it doesn't work. :/ Thank you.
class A
{
private $foo = 'bar';
function read()
{
echo self::$foo;
}
}
$a = new A();
a::read();
Strict Standards: Non-static method A::read() should not be called statically in /code/I0Zqoi on line 13
Fatal error: Access to undeclared static property: A::$foo in /code/I0Zqoi on line 8
The only workaround seems to be to add "static" in front of the method. Apparently, non-static methods cannot be accessed by static means (e.g., class A{function read(){echo "whatever"};} cannot be accessed by a::read() because the -> operator is necessary). Also, static properties cannot be accessed by object code, even if they exist within a function (e.g., class A{static $variable; function read(){echo $this->variable};} a->read(); won't work because the -> operator is being used to access a function that calls a static property.). By changing both the method and the property to static, the method can be accessed by static means. By changing both the method and property to non-static makes it so that either can be accessed with object instanciation. It doesn't make sense to me that the debugger is throwing errors because my book says that static properties can be called from non-static methods via object code calls to the non-static methods. So, is the debugger broken? Because I've tried every combination, and the code only seems to work if both the method and property are either static or non-static. :(((
The Strict Standards part is because a::read() is being called in a static context with ::. After declaring $a as a class instance of A, you should call the read() method on the variable using the -> operator:
// Proper non-static method call
$a = new A();
$a->read();
In the class definition, $foo is declared as a private property, but without the static keyword. It is then referred to in static context using the :: operator instead of the ->. The proper way to access it would beL
// Proper reference to non-static $foo
function read() {
echo $this->foo;
}
Now what does static mean anyway? Static methods and properties refer to class methods and properties that are shared by all current and future class instances. If A::$foo had been declared as:
private static $foo;
then there would be only the one $foo for all of class A in your code. Changing $foo would affect all instances of class A, and $foo can be accessed without even creating an instance of the class (like new A();)
Likewise, static methods can be called without creating an instance of the class because they do not modify class properties that are not also static.
// Static method call:
A::read();
To declare properties and methods as static, just add the static keyword:
// Property
private static $foo;
// Method
public static function foo() {}
EDIT for more examples:
class A
{
// Private property (non-static)
private $foo;
// Public property (static)
public static $bar = 12345;
// Public (non-static) function to access private $foo
public function getFoo() { return $this->foo; }
// Public (non-static) function to set private $foo
public function setFoo($newfoo) { $this->foo = $newfoo; }
// Static function
public static function incrementBar() { self::$bar++; }
}
Now see it in action:
// We haven't created any class instances yet (with the 'new' operator)
// But we can access the static properties & functions:
echo A::$bar . " ";
// prints 12345
A::incrementBar();
echo A::$bar . "\n";
// prints 12346
// Now we'll start working with class instances.
// Create 2 instances of class A
$a = new A();
$a->setFoo(8888);
$b = new A();
$b->setFoo(9999);
// It's a violation of strict standards to call getFoo() statically
// And it's meaningless to do so, because $foo only exists inside a class instance!
// Can't do this... Issues a strict warning since we're calling non-static getFoo() statically
//echo A::getFoo();
// But we can call getFoo() on the class instances:
echo $a->getFoo() . " " . $b->getFoo() . "\n";
// Prints 8888 9999
// Remember $bar was 12346...
echo $a::$bar . " " . $b::$bar . "\n";
// Prints 12346 12346
// Now modify the static property $bar again
// This affects all class instances.
A::incrementBar();
echo $a::$bar . " " . $b::$bar . "\n";
// Prints 12347 12347
I stuffed this whole thing into the codepad as well: http://codepad.viper-7.com/tV6omK
The book you're reading must not be paying attention to strict standards. If a non-static function does not attempt to access/modify a non-static property, you can call it statically successfully, but it WILL issue a strict warning. If the non-static function does modify or access a non-static property with $this->property, it will be a fatal error. You can't do that.
In PHP's error_reporting, the setting of E_ALL for show all errors actually does not include strict warnings. That has to be done with E_ALL & E_STRICT.
:: is used to access a static attribute. If you want to access an object attribute then use ->.
$a->read();
...
echo $this->$foo;
Although the other answers are definitely correct, here's an answer to your concrete question:
It doesn't make sense to me that the debugger is throwing errors because my book says that static properties can be called from non-static methods via object code calls to the non-static methods. So, is the debugger broken? Because I've tried every combination, and the code only seems to work if both the method and property are either static or non-static. :(((
The author of your book was under the impression that not getting an error message is considered clean code. It's not. You shouldn't have a method that can be called both statically as well as dynamically, as the two simply differ too much. Dynamic calls are for objects, where static calls are for classes. If you have the opportunity, I would always try to go the dynamic way, as that yields less coupling in the application.
As to why "the debugger is throwing errors" (it's the interpreter throwing E_STRICT warnings, but hey ;)): this behaviour has been changed in PHP five dot something. In PHP 4 you could call every method statically, even if it was a dynamic method. Possibly, your book is running behind on the facts.
What is the difference between these two pieces of code?
class something {
static function doit() {
echo 'hello world';
}
}
something::doit();
and the same but without the static keyword
class something {
function doit() {
echo 'hello world';
}
}
something::doit();
They both work the same is it better to use the static keywords? Am i right in understanding that it doesn't instantiate the class if you use the static method?
The second example is technically incorrect - if you turn on E_STRICT error reporting you'll see that PHP is actually throwing an error.
PHP Strict Standards: Non-static
method something::doit() should not be
called statically in...
In other words, it's being nice and letting you call the function anyway.
In addition to the other valid answers, the reason for the 2nd example working is also due to a quirk in how PHP handles objects and calls (Besides PHP 4 compatibility). Calling a non-static declared method statically from within another instance will let you access class methods on other classes as if they were local. To understand, let's take an example:
class A {
public function foo() {
echo get_class($this) . "\n";
}
}
class B {
public function bar() {
A::foo();
}
}
$a = new a();
$a->foo(); // "A"
$b = new B();
$b->bar(); // "B"
Did you see what happened there? Because you called the A::foo() method from within another class's instance, PHP treated the call as if it was on the same instance. Note that there is no relationship between A and B other than the fact that B calls A. Within A->foo(), if we did $this instanceof A (or $this instanceof self), it would fail and return false! Quite unusual...
Now, I first thought it was a bug, but after reporting it, it's apparently as designed. It's even in the docs.
Note that this will not work with E_STRICT mode enabled. It also will not work if you declare a method as static.
The difference is that static functions can be used without having to create an instance of the class.
Have a look at this great PHP OOP beginner tutorial here. It explains in more detail with an example under the Static Properties and Methods section.
Second bit shouldn't work as you should call it by
$something = new something();
$something->doit();
Static functions allows you to call a function within a class without consturcting it.
So basically if you have a class to handle users, so a function that logs the user in should be a static function, as in the constructor of that class you will probably gather the user information and you cannot do so without logging him in.
Your second example is wrong. Using a static method does not create an instance of the class. Your second example should look like this:
$x = new something();
$x->doit();
Static methods should be declared static for minimum two reasons:
a) when using E_STRICT error_reporting, calling non static method as static will generate error:
Strict standards: Non-static method something::doit() should not be called statically
b) based on keyword static some IDE's filter method possible to run at auto-complete.