Php: What If I Call a Static Method in Non-Static Way

PHP: What if I call a static method in non-static way

As Baba already pointed out, it results in an E_STRICT depending on your configuration.

But even if that's no problem for you, I think it's worth mentioning some of the pitfalls which may result from calling static methods in a non-static way.

If you have a class hierarchy like

class A {
public static function sayHello() {
echo "Hello from A!\n";
}

public function sayHelloNonStaticWithSelf() {
return self::sayHello();
}

public function sayHelloNonStaticWithStatic() {
return static::sayHello();
}
}

class B extends A {
public static function sayHello() {
echo "Hello from B!\n";
}

public function callHelloInMultipleDifferentWays() {
A::sayHello();
B::sayHello();
$this->sayHelloNonStaticWithSelf();
$this->sayHelloNonStaticWithStatic();
$this->sayHello();
}
}

$b = new B();
$b->callHelloInMultipleDifferentWays();

This produces the following output:

Hello from A!
// A::sayHello() - obvious

Hello from B!
// B::sayHello() - obvious

Hello from A!
// $this->sayHelloNonStaticWithSelf()
// self alweays refers to the class it is used in

Hello from B!
// $this->sayHelloNonStaticWithStatic()
// static always refers to the class it is called from at runtime

Hello from B!
// $this->sayHello() - obvious

As you can see, it's easy to achieve unexpected behaviour when mixing static and non-static method calls and techniques.

Therefore, my advice also is:
Use Class::method to explicitly call the static method you mean to call.
Or even better don't use static methods at all because they make your code untestable.

How to call non-static method from static method of same class?

You must create a new object inside the static method to access non-static methods inside that class:

class Foo {

public function fun1()
{
return 'non-static';
}

public static function fun2()
{
return (new self)->fun1();
}
}

echo Foo::fun2();

The result would be non-static

Later edit: As seen an interest in passing variables to the constructor I will post an updated version of the class:

class Foo {

private $foo;
private $bar;

public function __construct($foo, $bar)
{
$this->foo = $foo;
$this->bar = $bar;
}

public function fun1()
{
return $this->foo . ' - ' . $this->bar;
}

public static function fun2($foo, $bar)
{
return (new self($foo, $bar))->fun1();
}
}

echo Foo::fun2('foo', 'bar');

The result would be foo - bar

How to call a non-static method from a static function in a class in php

Just create an instance:

    public static function staticFun ($data) {
$instance = new ClassName($data);
echo $instance->anotherFun($data);
}

Note: you have a parameter $data for anotherFun, but you don't use it anywhere.

PHP Call non static function with static way

You will get Strict standards: Non-static method test::hello() should not be called statically

and your Class declaration is not good, right way is this

class test
{
public function hello()
{
return "say hello";
}
}

class foo
{
public function __construct()
{
echo test::hello();
}
}

$foo = new foo();

Laravel uses Facade to give illusion that you are using static method, you can also use Facade to call method like test::hello();

Here is a good read on Facade

php calling a non static method from a static method

It doesn't make any sense to want to call a non-static method from a static one. To call a non-static method, you need an object instance. When you call a method statically, you have no object instance. I hope the discrepancy is obvious.

The point of non-static methods is that they have access to instance-specific data:

class Foo {

public $bar;

public function baz() {
echo $this->bar;
}

}

$a = new Foo;
$b = new Foo;

$a->bar = 'Hello';
$b->bar = 'World';

$a->baz();
$b->baz();

The $this keyword is the special sauce here. Since you do not have an object instance in a static method, i.e. no $this, you cannot call a non-static method:

Foo::baz();  // now what?

If your function uses $this and requires an object instance, you cannot call it statically. If your function does not use $this and does not require an object instance, make it static and call it statically.

Make static out of non-static (Magic Method)

It will not work because you cannot call non static methods statically.
The reason why it works with methods like get() is because these calls are being delegated to the query instance - they don't actually exist on the model itself.

If you check __call method, it should all become a bit more clear:

public function __call($method, $parameters)
{
if (in_array($method, ['increment', 'decrement'])) {
return $this->$method(...$parameters);
}

return $this->newQuery()->$method(...$parameters);
}

So even though the default __callStatic method implementation calls the non static method on itself:

public static function __callStatic($method, $parameters)
{
return (new static)->$method(...$parameters);
}

Your code would fail straight away, because your model would actually contain the public non-static method with the same name.

You'll see that the __call method checks whether the name of the method is within the array of increment and decrement - and if it is - it calls them.

protected function increment($column, $amount = 1, array $extra = [])
{
return $this->incrementOrDecrement($column, $amount, $extra, 'increment');
}

protected function decrement($column, $amount = 1, array $extra = [])
{
return $this->incrementOrDecrement($column, $amount, $extra, 'decrement');
}

Both of these methods are actually non-static on the instance of the model, but their visibility is set to protected so you wouldn't be able to call them on the instance of the model anyway - the only way to access them is using magic methods - in this case static call will work just fine.

In other words, if you change visibility of your method to protected and overwrite the __call method to also include your method name in the array, then your code should work

protected function callThis()
{
return 'Yo';
}

public function __call($method, $parameters)
{
if (in_array($method, ['increment', 'decrement', 'callThis'])) {
return $this->$method(...$parameters);
}

return $this->newQuery()->$method(...$parameters);
}

Hope this helps.



Related Topics



Leave a reply



Submit