Weird behaviour with triggering __callStatic() from non-static method - php

I found this weird behaviour with PHP classes (v5.3.8).
You have:
class foo {
function __call($func, $args) {
if ($func == 'bar')
echo "non-static __call";
}
static function __callStatic($func, $args) {
if ($func == 'bar')
echo "__callStatic";
}
function callMe() {
self::bar();
}
}
Then you do:
foo::bar() // outputs '__callStatic' as expected.
$f = new foo;
$f->callMe(); // outputs 'non-static __call', as I did not expect.
You see, a non-existent static method called from a non-static function triggers __call() instead of __callStatic(). I was wondering if this is supposed to work like this or is this some kind of bug?
[EDIT]
I forgot to try static::bar(); on callMe() but no, it didn't work either.
I (think I) understand inhan's comment but still... if I'm calling the class itself, not the instance or object, immediate logic for me says it should trigger __callStatic(). Oh well.
Thank you for your answers/comments.

You might be confused by what these things mean from within the context of a class method:
class B extends A {
public function test() {
A::foo();
self::foo();
static::foo();
}
}
None of those mean "call the static method named foo." It simply means "call the method named foo" at the place in the inheritance tree as specified by what is left of the colons.
Normally, without magic, you only have one function named foo, so the meaning is straightforward. However, when you overload with both magic methods, the call is ambiguous. PHP defaults to using __call() before __callStatic().

Static methods, variables belongs to classes not to objects so i think this is supposed to work like this.

Related

Bad sign if I need a method of a class without calling a constructor because constructor needs parameters?

class Test
{
private $flag;
public function __construct($flag)
{
$this->flag = $flag;
}
public function a()
{
if ($this->flag)
{
$this->b();
}
}
public function b()
{
$this->c();
}
public function c()
{
}
}
how an external method would like to use b() but he cant do it without creating Test. But Test requires a parameter, even though it wont be used. b() also cant be static.
Answer to original question:
Yep, the best way to access the method of a class without instantiating it (instantiation requires parameters) is to make the desired method static. Make sure that it makes sense to use the method even if the object has not been constructed yet. Note that you cannot refer to non-static content, e.g. non-static methods, within a static context e.g. a static method.
Edit (question now specifies b() cannot be static):
If b() cannot be static then it must be referring to a non-static member e.g. a non-static function or variable. In other words, it must be referring to an instance variable that requires the instantiation of the object. It is not possible to call a non-static method of a class without instantiating the class. I would recommend you analyze the class structure and determine why b() must be non-static (trace any functions or variables it refers to).
Looking at the body of b(), it calls the non-static method c(). Analyze the body of c() and find out why c() must be non-static. If you cannot find any references to an instance of the object, you can safely make c() static and therefore make b() static. On the other hand, if c() requires an instance then b() will also require an instance meaning it is not possible to make b() static.
If you need to create the class without specifying the flag, then you can default the value:
public function __construct($flag = null)
{
$this->flag = $flag;
}
You can use other simple values instead of null. If you need to default it to something other than a simple value (i.e. you need to call another function), then you can check to see if $flag is null or not null. Then you can use the other functions as necessary.

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.

How does 'self' exactly work in inherited classes?

According to php, class::self always points to the class itself, but as I wrote down these codes, something strange happens:
class C_foo{
function foo() { return "foo() from C_foo"; }
function bar() { echo self::foo(); }
}
class C_bar extends C_foo{
function foo() { return "foo() from C_bar"; }
}
C_foo::bar();
C_bar::bar();
I thought the output would have been:
foo() from C_foo
foo() from C_bar
But in fact:
foo() from C_foo
foo() from C_foo
It means that the self in parent class does NOT exactly inherit into the child, it works more like to this:
foo() {return parent::foo();}
Is that a feature from php or is it a bug? Or is it mean to be like this?
Otherwise, such thing is occurred as I tried to tell a class create objects from itself, the code is something like this:
class Models {
function find($exp) {
...
...
$temp_model = new self();
...
...
}
}
class Something extends Models {...}
$somethings = Something::find("...");
Maybe someone would ask, "why don't you set a variable with the value of class, and use the variable as the __construction function?"
Like this:
...
...
function find($exp) {
...
...
$class_name = __class__;
$temp_model = new $class_name();
...
...
}
...
In fact I did that, and got a even more weird result:
It works only when the class does not have any property or function but find(), or an error telling me a variable shows off where a function sould exist would jump out.
It sounds like you're describing the PHP feature known as 'late static binding'.
PHP provides two syntaxes: self:: and static::.
static was introduced in PHP 5.3 because a lot of people expected self to work the you're describing.
See the PHP manual for more: http://php.net/manual/en/language.oop5.late-static-bindings.php
You can also use the syntax new self() or new static() to create new instances:
$parent = new self();
$child = new static();
This is because the class which receives the methods of the parent is of that class. So:
$bar is Bar, therefore self:: refers to Bar, not to Foo. Even though that method is from Foo.
This may be different from Java, but it probably indicates how PHP is doing inheritance internally.
In PHP, classes are not object. Because of that, there is no inheritance of static methods (actually, they are similar to global functions).
So, when C_foo says self, it always means C_foo (even if you called a method from C_bar).
If you want create instances from an abstract class method, you should try the Factory pattern.

what's the point of declaring static functions in PHP?

So in PHP you can have
Class A{
function B(){}
}
and you can call this as if it were a static function:
A::B();
My question is...if I can do this, then why should I ever declare the function B() as static since doing so makes $this unavailable, so there's less flexibility, so you have everything to lose but nothing to gain...
or is there an advantage of declaring the function as static that I'm not aware of?
also I heard that "static calling of non static methods" are "deprecated"....what does that exactly mean especially in relation to this scenario? is calling A::B() when B() is not declared static something that I shouldn't be doing? if so, why is that the case?
Because PHP tends to be a bit loosy-goosy around strictness (?) these sort of things work. The fact that they are deprecated means that sometime in a future release, it is likely not to work anymore. So if you are calling a non-static function in a static context, your program may break in a future PHP upgrade.
As for using it right now - the advantage to declaring a function as static is that you are deciding right there how that function should be used. If you intend to use a function in a static context, you can't use $this anyway, so you are better of just being clear on what you plan to do. If you want to use the function statically, make it static. If you don't, then don't. If you want to use a function both statically and non-statically, then please recheck your requirements :P
For compatibility mode. Now calling non-static methods statically generates an E_STRICT level warning.
Why static and not instantiate the object? Each programmer will tell you a reason. I particulary preffer instantiate object than use static methods. It's clear, traceable and more reusable.
I did a test bench and the difference was minimal between instantiate and call a method than call it staticaly.
Tip: if you foresee calling methods statically defines them as well;-)
First off, you couldn't do stuff like that in your post in a strict typed language like Java. Java code doesn't compile, if you call non-static stuff in a static context. PHP is not that strict on these things (yet), but still you shouldn't do things just because you can, although it's bad practice and in some languages even 'incorrect' practice.
There sure are advantages using static methods. And it's not quite right that you gain nothing or even lose flexibility. Let's have an example:
class A {
private static $prop_a = 'property_a';
public static function b() {
echo 'called b()';
echo self::$prop_a;
$A = new A();
$A->c();
}
public function c() {
echo 'called c()';
}
}
Now we can call the class this way:
A::b();
which outputs
called_b
property_a
called_c
But you can do the same with:
$a = new A();
$a->b();
$a->c();
c() is executed twice now, but you get the idea. Within your class, you can instanciate the class itself and work with it like with a regular object. But from outside, it's simply one line of code while it's 3 lines using the non-static way. Pretty cool, huh?
And as you see, you can use the static function in a non-static context, which means, you can declare your method static, but if you instanciate your class, you can simply call it like a regular method. Sounds pretty flexible to me ;)
And no, you can't use $this in a static context, but that's what self is for ;)
If it is a static function you don't have to instantiate the class in order to use the method.
Class A {
static function hello($arg)
{
echo 'Hello, ' . $arg;
}
}
A::hello('world');
VS
Class A {
public function hello($arg)
{
echo 'Hello, ' . $arg;
}
}
$a = new A;
$a->hello('world');
The important thing here is the instantiation of the object. After you've instantiated an object, it can be manipulated, and calling your methods may yield unexpected results. If your values and functions are statically declared in the class, they cannot be modified at the time you call the function.
This is not to say they you should always use static methods either. take the following example.
class My_math {
static function pi()
{
return 3.14
}
}
class My_bakery {
private var $pie;
function set_pie($pie)
{
$this->pie = $pie;
}
function pie()
{
echo "I made you a " . $this->pie . "pie";
}
}
I've made My_Math return a constant value, because I know pi doesn't change. But in My_bakery, some days I want blueberry pie and some days I want peach pie.

php static methods question

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.

Categories