Static variables, static properties and methods, and later static binding in PHP and OOP features

Lecture



What does the word "static" mean in PHP and why does it apply?

The static keyword has three different meanings in PHP. We analyze them in chronological order, as they appeared in the language.

The first value is a static local variable.

 function foo () {
   $ a = 0;
   echo $ a;
   $ a = $ a + 1;
 }

 foo ();  // 0
 foo ();  // 0
 foo ();  // 0



In PHP, variables are local. This means that the variable defined and received within the function (method) exists only during the execution of this function (method). When you exit the method, the local variable is destroyed, and when you re-enter, it is created anew. In the code above, such a local variable is the $ a variable - it exists only inside the foo () function and is created anew each time this function is called. The increment of a variable in this code is meaningless, since on the very next line of code the function ends its work and the value of the variable will be lost. No matter how many times we call the foo () function, it will always output 0 ...

However, everything changes if we assign the keyword static before assignment:

 function foo () {
   static $ a = 0;
   echo $ a;
   $ a = $ a + 1;
 }

 foo ();  // 0
 foo ();  // one
 foo ();  // 2



The static keyword written before assigning a value to a local variable results in the following effects:

  1. Assignment is performed only once, when the function is first called
  2. The value of a variable marked in this way is saved after the function ends.
  3. On subsequent function calls, instead of assignment, the variable gets the previously saved value.


This use of the word static is called a static local variable.

Pitfalls of static variables


Of course, as always in PHP, it does not do without “pitfalls”.

The first stone is that you can assign only constants or constant expressions to a static variable. Here is the code:

 static $ a = bar ();


will inevitably lead to parser error. Fortunately, starting with version 5.6, it became possible to assign not only constants, but also constant expressions (for example, “1 + 2” or “[1, 2, 3]”), that is, such expressions that are independent of other code and can be computed at compile time

Stone two - methods exist in a single copy.
It's all a little more complicated. To understand the essence I will give the code:

 class A {
   public function foo () {
     static $ x = 0;
     echo ++ $ x;
   }
 }

 $ a1 = new A;
 $ a2 = new A;

 $ a1-> foo ();  // one
 $ a2-> foo ();  // 2
 $ a1-> foo ();  // 3
 $ a2-> foo ();  // four


Contrary to the intuitive expectation of “different objects - different methods”, we clearly see in this example that dynamic methods in PHP “do not multiply”. Even if we have a hundred objects of this class, the method will exist only in one instance, just with each call it will be forwarded to a different $ this.

Such behavior may be unexpected for an unprepared developer and cause errors. It should be noted that the inheritance of the class (and method) leads to the fact that after all a new method is created:

 class A {
   public function foo () {
     static $ x = 0;
     echo ++ $ x;
   }
 }

 class B extends A {
 }

 $ a1 = new A;
 $ b1 = new B;

 $ a1-> foo ();  // one
 $ b1-> foo ();  // one
 $ a1-> foo ();  // 2
 $ b1-> foo ();  // 2



Conclusion: dynamic methods in PHP exist in the context of classes, not objects. And only in runtime there is a substitution "$ this = current_object"

Second value - static properties and methods of classes


In the PHP object model, it is possible to set properties and methods not only for objects — instances of a class, but also for a class as a whole. The static keyword is also used for this:

 class A {
   public static $ x = 'foo';
   public static function test () {
     return 42;
   }
 }

 echo A :: $ x;  // 'foo'
 echo A :: test ();  // 42


To access these properties and methods, double-colon constructions (“Paamayim Nekudotayim”) are used, such as CLASSNAME :: $Variable name and CLASSNAME :: MethodName ().

It goes without saying that static properties and static methods have their own characteristics and their own “pitfalls” that you need to know.

Feature one, banal - no $ this. Actually, this stems from the very definition of a static method — since it is associated with a class, not an object, the pseudo-variable $ this is not available in it, indicating the current object in dynamic methods. Which is completely logical.

However, you need to know that, unlike other languages, PHP does not define the situation “in the static method $ $ is written” at the stage of parsing or compilation. Such an error can occur only in runtime if you try to execute code with $ this inside a static method.

A code like this:

 class A {
   public $ id = 42;
   static public function foo () {
     echo $ this-> id;
   }
 }


will not lead to any errors unless you try to use the foo () method in an inappropriate way:

 $ a = new A;
 $ a-> foo ();

(and immediately get "Fatal error: Using $ this when not in object context")

The second feature - static is not an axiom!

 class A {
   static public function foo () {
     echo 42;
   }
 }

 $ a = new A;
 $ a-> foo ();


So, yes. A static method, if it does not contain in the code of $ this, it is possible to call it in a dynamic context, as a method of an object. This is not a PHP error.

The reverse is not quite true:

 class A {
   public function foo () {
     echo 42;
   }
 }

 A :: foo ();


A dynamic method that does not use $ this can be executed in a static context. However, you will receive the “Non-static method A :: foo () should not be called statically” warning of the E_STRICT level. Here you decide - or strictly follow the standards of the code, or suppress warnings. The first, of course, is preferable.

And by the way, everything written above applies only to methods. Using a static property through "->" is impossible and leads to a fatal error.

The value of the third, seemingly the most difficult - late static binding


The developers of the PHP language did not stop at two meanings of the “static” keyword and, in version 5.3, added another “feature” of the language, which is implemented with the same word! It is called “late static binding” or LSB (Late Static Binding).

The simplest examples are to understand the essence of LSB:

 class Model {
   public static $ table = 'table';
   public static function getTable () {
     return self :: $ table;
   }
 }

 echo Model :: getTable ();  // 'table'


The self keyword in PHP always means "the name of the class where the word is written." In this case, self is replaced with the Model class, and self :: $ table with Model :: $ table.
This language feature is called “early static linking”. Why early? Because the binding of self and a specific class name occurs not in runtime, but at earlier stages - parsing and compiling code. Well, "static" - because we are talking about static properties and methods.

Let's change our code a bit:

 class Model {
   public static $ table = 'table';
   public static function getTable () {
     return self :: $ table;
   }
 }

 class User extends Model {
   public static $ table = 'users';
 }

 echo User :: getTable ();  // 'table'



Now you understand why PHP behaves unintuitively in this situation. self was associated with the Model class when nothing was known about the User class, and therefore points to Model.

How to be?

To solve this dilemma, the mechanism of binding the “late” was invented, at the runtime stage. It works very simply - it is enough to write “static” instead of the word “self” and the connection will be established with the class that calls this code, and not with where it is written:

 class Model {
   public static $ table = 'table';
   public static function getTable () {
     return static :: $ table;
   }
 }

 class User extends Model {
   public static $ table = 'users';
 }

 echo User :: getTable ();  // 'users'



This is the mysterious "later static binding".

It should be noted that for more convenience in PHP, in addition to the word "static", there is also a special function get_called_class () that will tell you what context your code is currently running in.

example How to calculate the number of objects in a class in PHP?

Every time we create (create) a new object, we can track it through a static property. Thus, we can count the number of objects created for this class.

At the moment, PHP does not have a built-in function that counts the number of objects in a class, so you can create it yourself.

We create a static property (because it is not tied to an object, but to a class), and we place it inside the constructor. Because the constructor is called every time an object is instantiated, we add a static value increment, keeping the score by 1 for each object instance, we can track the number of objects in the class.

So, in the following PHP code, we created a program that counts the number of objects created for a class in PHP.

 

  class animals 
  { 

  public static $ count = 0; 

  public function __construct ($ type, $ year) 
  { 
  $ this-> type = $ type; 
  $ this-> year = $ year; 
  animals :: $ count ++; 
  return true; 
  } 

  } 

  $ animal 1 = new animals ("Dog", 2018); 
  $ animal 2 = new animals ("Cat", 2012); 
  $ animal 3 = new animals ("Mouse", 2010); 

  echo "The number of objects in the class is".  animals :: $ count; 

  ?> 

 
 

So in this code we create a class named animals.

We declare a public static property named $ count and set it to 0. This variable will be used to count the number of objects created in the class.

Then we create a constructor for the class. Since this is a class that represents animals, each created object is an object of an animal (it represents an animal). We want to transfer to animals the properties Nicknames and year of birth.

Therefore, in the constructor, we pass the arguments $ type and $ year, representing the Nickname and the year of the animal.

Then we use the $ this keyword to assign the type and year values ​​to the $ type and $ year variables.

Then we use the increment operator to increase the animals :: $ count property.

Because the constructor is called every time an object is created, we can use this fact to keep track of how many objects are created. Initially, the variable animals :: $ count is 0. However, with each instance that is created, the score increases by 1. Thus, we can find out how many objects were created.

Since we created 3 animals, at the end of this program you will see that the program will display that 3 objects have been created.

The number of objects in the class is 3

Keeping counting the number of objects if they are deleted

You could make this program a bit more complicated.

For example, what if an object is destroyed? What if we delete one or more objects after they are created?

In this case, you will also need to create a destructor function for the class. When an object is destroyed (if you delete an object), you put it in the destructor function, the decrement operator for animals :: $ count . Therefore, if an object is destroyed, the counter is decreased by 1. Thus, you can track how many objects currently exist for a class.

So, below is the code that tracks all currently existing objects in the class. If the object is created, the counter is incremented by 1. If the object is destroyed, the counter is reduced by 1.


 

  class animals 


  { 

  public static $ count = 0; 

  public function __construct ($ type, $ year) 
  { 
  $ this-> type = $ type; 
  $ this-> year = $ year; 
  animals :: $ count ++; 
  return true; 
  } 

  public function __destruct () 
  { 
  animals :: $ count--; 
  } 

  } 

  $ animal1 = new animals ("Mouse", 2014); 
  $ animal2 = new animals ("Dog", 2012);  
  unset ( $ animal2 ); 
  $ animal3 = new animals ("Dug", 2019); 

  echo "The number of objects in the class is".  animals :: $ count; 

  ?> 

Thus, the whole code is basically the same, but now we have a class destructor, and we intentionally delete the $ animal2 object. Inside the destructor, we have the variable animals :: $ count, decreasing by 1 each time the destructor is called. And the destructor function is called when we delete an object using the PHP unset () function. Therefore, whenever we delete an object, the counter is decremented by 1.

So, now, when we run our code, now, when we delete one of the objects, the score will be 2.

Instead of specifying the class name, you can use the self keyword, that is, instead of animals :: $ count (only), you can use self :: $ count inside the class .

Therefore, using a static variable is a very efficient and easy way to track the number of objects in a class.

Since a static variable is not bound to an object and is instead bound to a class, it does not depend on any object in the class. Therefore, it has an appearance, so to speak, and can track all objects in a class.

This way, you can track the number of objects in a class in PHP.

Static methods or properties are also used when initialization of an object is unnecessary and method variables do not depend on object properties.


Comments


To leave a comment
If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Running server side scripts using PHP as an example (LAMP)

Terms: Running server side scripts using PHP as an example (LAMP)