The static keyword was introduced in PHP5, which kinda makes one come to the conclusion that PHP4 didn't support static methods or variables. And yet when I run the following code on PHP 4.4.9 it works without the constructor ever being called.
<?php
class a {
function a() {
echo "CONSTRUCTOR CALLED\r\n";
}
function b($var) {
return $var . 'x';
}
}
print_r(array_map(array('a', 'b'), array('a', 'b')));
You can play around with the code with this PHP "fiddle":
http://sandbox.onlinephpfunctions.com/code/1d6882a8264620a0165d7345791f8680586a869e
Any ideas as to how this is working?
All the static keyword does is tell PHP that a function should be called statically. In actual fact, even the latest versions will let you call any function statically if you want, as this online demo with your code in multiple PHP versions shows.
If you turn error reporting to the max, as in this demo you will see that newer versions of PHP give an E_STRICT message that you're using a function statically that hasn't been declared as such, but otherwise run the code exactly as before.
All that's needed to make a static function call is ::, and that was present and correct in PHP 4. It's really the non-static methods that were tidied up in PHP 5, and further in 5.3
Related
I've found some odd behaviour in some legacy code that I am trying to understand. I have boiled it down to a simple test-case.
<?php
class Foo {
function DoFoo() {
print("[" . get_called_class() . "]");
}
}
class Bar {
function DoBar() {
Foo::DoFoo();
}
}
// Called by direct static call.
Foo::DoFoo();
// Called by indirect static call, without an object context.
Bar::DoBar();
// Called by indirect static call, from within an (unrelated) object context.
// (But still, ultimately, a static call).
$Bar = new Bar();
$Bar->DoBar();
This code gives the following output:
[Foo][Foo][Bar]
However, the description of get_called_class() says that this function "Gets the name of the class the static method is called in.". As DoFoo() is always called statically on the Foo class, you would therefore expect get_called_class() to return Foo, in which case you should get the following output:
[Foo][Foo][Foo]
Ignore the fact that the above code generates strict standards warnings (these are suppressed in the original code-base) and that the issue being described can be fixed by properly declaring the static functions as static (which is the correct 'solution' to the problem). What I am interested in, for the sake of my curiosity, is why PHP emits this output in these circumstances.
Is this a PHP bug?
If so, why has it never been fixed?
Or, if not, what is the rationale for this unintuitive output?
Update
It has been pointed out in the comments that PHP 7 behaves as described. This problem therefore only exists between PHP 5.3 (where late static binding was introduced) and 5.6. (demonstration)
I would still be interested to know why it took so long to fix it as it seems like an obvious (and, in some cases, critical) mistake, but maybe it was just standard open-source inertia.
If anyone has anything to add in that regard, I'd be happy to accept an answer that provides the information (e.g. link to/summary of a bug report), otherwise I'll close this down in a day or two.
Ignore the fact that the above code generates strict standards warnings (these are suppressed in the original code-base)
Those warnings should not be supressed. The warning is "Non-static method Foo::DoFoo() should not be called statically".
If you declare DoFoo() as a static method then on PHP 5 get_called_class() will work as you expect it to work (and how it does work in PHP 7).
It appears to me that in certain versions of PHP, the Late Static Binding feature only works correctly on methods declared as static.
(PHP7)
Consider the following code, which tries to assign a function to a variable, and then make sure it is called only once.
class a{
static public $b;
static public function init(){
self::$b();
self::$b=function(){};
}
}
a::$b=function(){echo 'Here I do very heavy stuff, but will happen only in the first time I call init()';};
for($i=0;$i<1000;$i++){
a::init();
}
In php7 it will give an error that it expects a::$b to be a string (the function name to call).
If I use pure variables and not static members, it will work.
My question, is this suppose to work, or not, or is there a small tweak I can do for this to work without pure vars?
You can either use PHP 7 Uniform Variable Syntax:
(self::$b)();
Or a temporary variable in PHP 5+ (including 7):
$init = self::$b;
$init();
As seen on 3v4l.org.
I just wrote a sample class to better understand the static methods and variables in PHP. I understand how the static variables work but the static function is not working as expected. If you see the below code
class Car{
static $wheels=4;
static function getWheels(){
echo Car::$wheels=10;
}
}
$car1 = new Car();
$car1->getWheels();
I was expecting
$car1->getWheels(); to throw and error since getWheels is a static method.
Why is this not throwing an error or warning?
I think it comes from the PHP 4 times, where there was no static keyword but you could call static methods whether with the -> or the :: operator
In fact, tecnically speaking, calling $car1->getWheels() was (and is) translated by PHP to Car::getWheels() at run time
With the advent of PHP5 this option was mantained for backward compatibility purposes
If you enable E_STRICT error reporting though, this should raise a warning now
I was reading a book about PHP when I ran into a strange part of code:
class Employee {
public function show() {
echo "show launched\n";
}
}
Employee::show();
I came from C++ so I was going to bet this code wouldn't work. This is why I tested it.
And it worked, showing "show launched" (omg, am I drunk?)!
It seems to be breaking the concept that method of class can be called without instantiation of class.
What is the point then of static identifier in classes?
Are all public functions static too? Really, what am I missing?
Thanks in advance.
Addition:
Just a notice.
I found that in this book.
Pages 178-179 and it's given as correct example (if I'm right)
Yeah that would work but with a warning. You may have turned off your error reporting on PHP by the way...
Strict standards: Non-static method Employee::show() should not be
called statically
Adding a static keyword before the function definition would make the warning dissappear.
Below code works without a warning..
<?php
class Employee {
public static function show() { //<----- Added the static keyword.
echo "show launched\n";
}
}
Employee::show();
To answer your question...
It seems to be breaking the concept that method of class can be called
without instantiation of class.
Yeah that is correct, that's why you are getting a pretty clear cut warning as I showed you earlier. You know what a warning does right ? ;). Something that should not be done.
From the PHP Docs..
Calling non-static methods statically generates an E_STRICT level
warning.
Source
It has different behavior related on php version. PHP 4 did not have a static keyword (in function declaration context) but still allowed methods to be called statically with ::. This continued in PHP 5 for backwards compatibility purposes.
However with the changes in the object model with PHP 5 - the static keyword has been introduced.
And then since PHP 5.1.3 you get proper strict standard warnings about those like:
Strict Standards: Non-static method Employee::show() should not be called statically in ...
I think it depends on php version you are using. This feature is deprecated in the new php version and will be removed in the future versions.
this will not work and you will get error when using the latest php versions.
I am using PHP 5.5.9-1+sury.org~precise+1 (cli) (built: Feb 13 2014 15:53:53)
and if turn errors on and put your code as it is.
<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
class Employee {
public function show() {
echo "show launched\n";
}
}
Employee::show();
?>
This is error message I am getting.
**Strict Standards: Non-static method Employee::show() should not be called statically in /var/www/test/index.php on line 19
show launched**
The Code Works you will get a Warning
Strict standards: Non-static method Employee::show() should not be called statically
Just add the static keyword in the function like public static function show()
I thought that the use of the static keyword in the declaration of a class function meant that you could call the function without an instance of the class using the scope resolution operator (::).
For example:
class Foo
{
public static function static_function() {
return 'x';
}
public function non_static_function() {
return 'y';
}
}
// to call static_function:
echo Foo::static_function();
// to call non_static_function:
$foo = new Foo();
echo $foo->non_static_function();
The PHP.net documentation on static seems to support this idea.
I came across some code yesterday that someone had wrote accessing class functions using the scope resolution operator that had NOT been defined with the static keyword. I was surprised and confused to see this worked.
Given my class defined above, Foo, it turns out you can actually do:
echo Foo::static_function();
echo Foo::non_static_function();
Resulting in output xy without generating any errors or warnings.
If you can access non-static class functions without the static keyword, what is the point in it?
Resulting in output xy without generating any errors or warnings.
No way. The error reporting must have been turned off on that environment. That would have definitely produced a Strict Standards warning notice.