4

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:

  1. Call an instance method statically;
  2. Call an instance method non-statically;
  3. Call a static method statically;
  4. 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?

  • 1
    Regarding the "How would the code look for calling a method statically from a secondary object?", please, read the example "Example #2 Some examples of the $this pseudo-variable" from the docs. – sevavietl Mar 31 '18 at 15:58
  • So in the Example #2 class B is the secondary object and this is calling the method statically from that -> "A::foo();"? "Calling statically" can be recognized by the "::" sign? –  Mar 31 '18 at 16:01
  • yes. Excuse me, but I think you read into static/dynamic a bit too much. The naming can confuse you. From my point of view, it is better to use Ruby lingo and call a static method a _class method_ and usual method an _instance method_. It helps to understand the difference better. – sevavietl Mar 31 '18 at 16:08
  • I am reading the php.net manual and I am trying to understand what is there. I am learning the PHP only and I am not familar with the Ruby yet. Basically I want to figure out the most basic things and go from there. Like there is instance and static methods (just these two types). Then you can call any of these statically and non-statically and so on. After I have that figured out (the "skeleton of knowledge" that I am not sure about) I could go from there. Also, if calling statically can be translated to using "::" (so I can recognize it by this). –  Mar 31 '18 at 16:12

2 Answers2

3

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:

  1. Call an instance method statically;
    • you can but shouldn't because $this is not exists
  2. Call an instance method non-statically;
    • this is normal
  3. Call a static method statically;
    • this too is normal
  4. 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.

ArtisticPhoenix
  • 21,464
  • 2
  • 24
  • 38
  • Would you be able to answer the exact questions that I had. I am not understanding the aspects of this. I am aware of the fact that calling a non-static method statically used to emit an error in PHP 5.3.0 and this is even different now. –  Mar 31 '18 at 15:54
  • I had never even considered using static methods because I heard that they were "evil"... What I see from this is that it allows you to access a method as if it were just a plain old function (with double colons in the name). But there's obviously more to it than the ease of writing `Foo::biz()` instead of `(new Foo)->biz()`. I'll have to digest your answer for a while. :) – Tim Morton Mar 31 '18 at 16:40
0

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.

Felippe Duarte
  • 14,901
  • 2
  • 25
  • 29
  • Thanks for the answer. In general, there is static and instance methods only (just these two types)? And then we can all any of these statically and non-statically? Calling statically would be denoted by using the "::" sign? These are the things that I dont understand. –  Mar 31 '18 at 16:04
  • Yes. Static means you don`t need a object instance ($var = new Class). You can call it from the class (Class::method). Objects are used when you need a state, among other things. When you are just doing simple things without the need of a state, you can use static methods. – Felippe Duarte Mar 31 '18 at 16:06
  • @ThomasMorgan - there is also `Magic` methods, you already have used these such as `__construct()` But there are many more that do ... interesting things. But that is like a whole other topic. – ArtisticPhoenix Mar 31 '18 at 16:22