(Late Static Binding, LSB) has been a hot topic for the last three years in PHP development circles (and finally we got it in PHP 5.3). But why is it needed? In this article, it will just be considered how late static linking can greatly simplify your code.

At the PHP Developers Meeting in Paris in November 2005, the topic of late static linking was formally discussed by the core development team. They agreed to implement it, along with many other topics that were on the agenda. The details were to be agreed upon through open discussions.

Since late static linking was announced as an upcoming feature, two years later. Finally, LSB became available for use in PHP 5.3. But this event passed unnoticed for developers using PHP, from the notes only a page in the manual.

In short, the new functionality of late static binding allows objects to still inherit methods from their parent classes, but in addition to this, it allows inherited methods to have access to static constants, methods and properties of the descendant class, and not just the parent class. Let's take an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

class Beer (
const NAME = "Beer!" ;

return self :: NAME;
}
}
class Ale extends Beer (
const NAME = "Ale!" ;
}

$ beerDrink = new Beer;
$ aleDrink = new Ale;

echo "Beer is:". $ beerDrink -> getName (). " \ n ";
echo "Ale is:". $ aleDrink -> getName (). " \ n ";

This code will give this output:

Beer is: Beer!

Ale is: Beer!

Class Ale inherited method getName () but at the same time self still points to the class in which it is used (in this case, it is the class Beer). This remained in PHP 5.3, but the word was added static... Let's look at an example again:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

class Beer (
const NAME = "Beer!" ;
public function getName () (
return self :: NAME;
}
public function getStaticName () (
return static :: NAME;
}
}

class Ale extends Beer (
const NAME = "Ale!" ;
}

$ beerDrink = new Beer;

$ aleDrink = new Ale;

echo "Beer is:". $ beerDrink -> getName (). " \ n ";
echo "Ale is:". $ aleDrink -> getName (). " \ n ";

echo "Beer is actually:". $ beerDrink -> getStaticName (). " \ n ";
echo "Ale is actually:". $ aleDrink -> getStaticName (). " \ n ";

New keyword static indicates that it is necessary to use the constant of the inherited class, instead of the constant that was defined in the class where the method is declared getStaticName ()... Word static was added to implement new functionality, and for backward compatibility self works the same as in previous versions of PHP.

Internally, the main difference (and, in fact, the reason why the binding was called late) between these two access methods is that PHP will define a value for self :: NAME during "compilation" (when PHP symbols are converted to machine code that will be processed by the Zend engine), and for static :: NAME the value will be determined at startup (at the moment when the native code is executed in the Zend engine).

This is another tool for PHP developers. In the second part, we will look at how it can be used for good.

  • Tutorial

It's no secret that they like to ask tricky questions in interviews. Not always adequate, not always related to reality, but the fact remains - they ask. Of course, the question is different to the question, and sometimes a question that at first glance seems stupid to you is actually aimed at testing how well you know the language in which you write.

Let's try to disassemble one of these questions "bit by bit" - what does the word "static" mean in PHP and why is it used?

The static keyword has three different meanings in PHP. Let us 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 a variable defined and assigned a value inside a function (method) exists only during the execution of this function (method). When the method exits, the local variable is destroyed, and when the method is entered again, it is recreated. In the code above, such a local variable is the variable $ a - it exists only inside the foo () function and is created anew each time this function is called. Incrementing a variable in this code is meaningless, because on the next line of code the function will finish 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 put the static keyword before the assignment:

Function foo () (static $ a = 0; echo $ a; $ a = $ a + 1;) foo (); // 0 foo (); // 1 foo (); // 2

The static keyword, written before assigning a value to a local variable, has the following effects:

  1. The assignment is performed only once, the first time the function is called
  2. The value of the variable marked in this way is saved after the end of the function
  3. On subsequent calls to the function, instead of assignment, the variable receives the previously saved value
This use of the word static is called static local variable.
Static variable pitfalls
Of course, as always in PHP, there are some pitfalls.

The first stone is that only constants or constant expressions can be assigned to a static variable. Here's the code:
static $ a = bar ();
will inevitably lead to a parser error. Fortunately, since version 5.6, it has become permissible to assign not only constants, but also constant expressions (for example - "1 + 2" or ""), that is, such expressions that do not depend on other code and can be calculated at compile time

The second stone - the methods exist in a single copy.
Everything is a little more complicated here. 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 (); // 1 $ a2-> foo (); // 2 $ a1-> foo (); // 3 $ a2-> foo (); // four
Contrary to the intuitive expectation “different objects - different methods”, we can clearly see in this example that dynamic methods in PHP “do not propagate”. Even if we have one hundred objects of this class, the method will exist in only one instance, just a different $ this will be passed into it each time it is called.

This behavior can be unexpected for an untrained developer and can be a source of errors. It should be noted that inheriting a class (and a method) leads to the fact that a new method is still created:

Class A (public function foo () (static $ x = 0; echo ++ $ x;)) class B extends A () $ a1 = new A; $ b1 = new B; $ a1-> foo (); // 1 $ b1-> foo (); // 1 $ a1-> foo (); // 2 $ b1-> foo (); // 2

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

Second meaning - 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 the 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 such properties and methods, double-colon ("Paamayim Nekudotayim") constructs such as CLASSNAME :: $ VariableName and CLASSNAME :: MethodName () are used.

It goes without saying that static properties and static methods have their own quirks and pitfalls to be aware of.

The first feature is banal - there is 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, which points to the current object in dynamic methods. Which is perfectly logical.

However, you need to know that, unlike other languages, PHP does not detect the situation "$ this is written in a static method" at the stage of parsing or compilation. This error can only occur at 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 is that static is not an axiom!
class A (static public function foo () (echo 42;)) $ a = new A; $ a-> foo ();
That's right, yes. A static method, if it does not contain $ this in your code, can be called in a dynamic context like an object method. This is not a bug in PHP.

The converse is not entirely 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 an E_STRICT level warning "Non-static method A :: foo () should not be called statically". It's up to you to decide whether to strictly follow the code standards or suppress warnings. The former is, of course, preferable.

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

The third, seemingly most difficult, meaning is late static linking.

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

The easiest way to understand the essence of LSB is to use simple examples:

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 this word is written". In this case, self is replaced with the Model class, and self :: $ table is replaced with Model :: $ table.
This language feature is called early static binding. Why early? Because the binding of self and a specific class name does not occur at runtime, but at earlier stages - parsing and compiling the code. Well, "static" - because we are talking about static properties and methods.

Let's change our code a little:

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 at a time when nothing was known about the User class, which is why it points to Model.

How to be?

To solve this dilemma, a mechanism for linking "late", at the runtime stage, was invented. 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 the given code, and not with the one 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 cryptic "late static binding".

It should be noted that for greater convenience in PHP, besides the word "static", there is also a special function get_called_class (), which will tell you in the context of which class your code is currently running.

Happy interviews!

Reg.ru: domains and hosting

The largest registrar and hosting provider in Russia.

More than 2 million domain names in service.

Promotion, mail for domain, business solutions.

More than 700 thousand customers around the world have already made their choice.

* Hover your mouse to pause scrolling.

Back forward

Static Methods and Properties in PHP

In the previous materials, we have mastered the basic features of object-oriented programming in PHP and now we turn to the study of more complex and interesting aspects.

Before that, we have always worked with objects. We have characterized classes as templates through which objects are created, and objects as active components whose methods we call and whose properties we access.

This led to the conclusion that in object-oriented programming, the real work is done using class instances. And classes are ultimately just templates for creating objects.

But in reality, not everything is so simple. We can access both methods and properties in the context of a class, not an object. Such methods and properties are called "static" and must be declared using the keyword static.

Class StaticExample (static public $ aNum = 0; static public function sayHello () (print "Hello!";))

Static methods are functions used in the context of a class. They themselves cannot access any of the normal properties of the class, because such properties belong to objects.

However, from static methods, as you probably already guessed, you can access static properties. And if you change a static property, then all instances of this class will be able to access the new value.

Since the static element is accessed through the class and not through the object instance, we don't need a variable that refers to the object. Instead, the class name is used, followed by two colons "::".

Print StaticExample :: $ aNum; StaticExample :: sayHello ();

You should already be familiar with this syntax from the basics of OOP in PHP. We used the construction "::" in combination with the keyword parent in order to access the overridden method of the parent class.

Now, as then, we are referring to the class, not the data contained in the object. You can use the keyword in the class code parent in order to access the superclass without using the class name.

To access a static method or property from the same class (and not from a child class), we will use the keyword self.

Keyword self is used to refer to the current class, and the pseudo variable $ this- to the current object. Therefore, from outside the class StaticExample we refer to the property $ aNum using the name of its class.

StaticExample :: $ aNum;

And inside the class StaticExample you can use the keyword self.

Class StaticExample (static public $ aNum = 0; static public function sayHello () (self :: $ aNum ++; print "Hello! (". Self :: $ aNum. ") \ N";))

Note: except when referring to an overridden method of the parent class, the "::" construct should always be used only for accessing static methods or properties.

By definition, static methods are not called in the context of an object. For this reason, static methods and properties are often referred to as class variables and properties. As a consequence, you cannot use the pseudo variable $ this inside a static method.

Why use a static method or property at all?

Here we come to the most important question. The point is that static elements have a number of useful characteristics.

Firstly, they are accessible from anywhere in the script (assuming you have access to the class). This means that you can access functions without passing an instance of a class from one object to another, or worse, by storing an instance of the object in a global variable.

Secondly, a static property is available to every instance of an object of this class. Therefore, you can define values ​​that should be available to all objects of a given type.

And finally third, the very fact that you don't need to have an instance of a class to access its static property or method will avoid instantiating objects solely for the sake of calling a simple function.

To demonstrate this, let's create a static method for the class ShopProduct which will automatically instantiate objects ShopProduct... Define a table using SQLite products in the following way:

CREATE TABLE products (id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT, firstname TEXT, mainname TEXT, title TEXT, price float, numpages int, playlength int, discount int)

Now let's create a method getInstance (), which is passed a string identifier and a PDO object. They will be used to retrieve a row from a database table, on the basis of which an object of type ShopProduct returned to the calling program.

We can add these methods to the class ShopProduct which was created for us in earlier materials. As you probably know, PDO stands for PHP Data Object. The PDO class provides a generic interface for various database applications.

// ShopProduct class private $ id = 0; public function setID ($ id) ($ this-> id = $ id;) // ... public static function getInstance ($ id, PDO $ pdo) ($ stmt = $ pdo-> prepare ("select * from products where id =? "); $ result = $ stmt-> execute (array ($ id)); $ row = $ stmt-> fetch (); if (empty ($ row)) (return null;) if ($ row ["type"] == "book") ($ product = new BookProduct ($ row ["title"], $ row ["firstname"], $ row ["mainname"], $ row ["price"] , $ row ["numpages"]);) else if ($ row ["type"] == "cd") ($ product = new CdProduct ($ row ["title"], $ row ["firstname"], $ row ["mainname"], $ row ["price"], $ row ["playlength"]);) else ($ product = new ShopProduct ($ row ["title"], $ row ["firstname"], $ row ["mainname"], $ row ["price"]);) $ product-> setId ($ row ["id"]); $ product-> setDiscount ($ row ["discount"]); return $ product;) // ...

As you can see, the method getInstance () returns an object of type ShopProduct, and he is "smart" enough to, based on the value of the field type create an object with the desired characteristics.

I've omitted the error handling code on purpose to keep the example as concise as possible. For example, in the actually working version of this code, we cannot be too gullible and assume that the transferred PDO object was correctly initialized and connected to the required database.

In fact, we should probably wrap the PDO object in a class that guarantees this behavior. We will return to this issue in a future article.

Method getInstance () more useful in the context of a class than in the context of an object. It allows you to easily convert the data that is in the database into an object, and for this we do not need to have a separate instance of an object of type ShopProduct.

This method does not use any methods or properties that require a separate instance of the object, so there is no reason not to declare it static. Then, having the correct PDO object, we can call this method from anywhere in the application.

$ dsn = "sqlite: //home/bob/projects/products.db"; $ pdo = new PDO ($ dsn, null, null); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ obj = ShopProduct :: getInstance (1, $ pdo);

Methods like these work like "factories" in that they take "raw" materials (such as data retrieved from a database string or configuration file) and use them to create objects.

The term "factory" refers to code for instantiating objects. We will meet with you further with examples of such "factories".


Permanent properties

Some properties should not be changed. For example, items such as error codes or program status codes are usually set manually in classes. While they should be public and static, client code should not be able to modify them.

To do this, you can define persistent properties within the class. Like global constants, class constants cannot be changed after they have been defined. A persistent property is declared using the keyword const.

Unlike regular properties, there is no dollar sign in front of the persistent property name. By convention, they are often assigned only uppercase names, as in the following example:

Class ShopProduct (const AVAILABLE = 0; const OUT_OF_STOCK = 1; // ...

Constant properties can only contain values ​​that are of an elementary type. You cannot assign an object to a constant.

As with static properties, persistent properties are accessed through the class, not through an object instance. Just as a constant is defined without a dollar sign, it also does not require any leading character to be accessed.

Print ShopProduct :: AVAILABLE;

Attempting to assign a value to a constant after it has been declared will result in an error during the parsing step.

Constants should be used when the property must be accessible to all instances of the class and when the property value must be fixed and unchanged.

This concludes this article, and the next one will focus on.

Did you like the material and want to thank you?
Just share with your friends and colleagues!


PHP has the ability to define a method as static. A static method does not have access to object properties. Such methods can only be called in the context of a class, not in the context of an object.

The most important thing to understand is that static properties and methods belong to classes, not objects.

An example will immediately become clear. Let's create a Math object (short for mathematics in English).

PHP static methods
"; $ math_1 = new Math (); $ math_2 = new Math (); $ math_3 = new Math (); $ math_4 = new Math (); echo" Objects created: ". Math :: getCount ();?>

This class provides tools for working with mathematical functions without having to create an object. The class has a constructor that increments the static property $ count by one. The class remembers the value of this property because it is static.

By the way, the word static is used to declare a method or property as static, and the word self with a double colon "::" is used to access a static property.

All of this is better understood by comparison, especially when comparing a working example with a faulty one. Let's expand our example a bit.

PHP static methods counter ++; ) public static function calcSin ($ x) (return sin ($ x);) public static function calcSQRT ($ x) (return sqrt ($ x);) public static function getCount () (return self :: $ count;) public function getCounter () (return $ this-> counter;)) echo Math :: calcSin (1); echo "
"; echo Math :: calcSQRT (9); echo"
"; $ math_1 = new Math (); $ math_2 = new Math (); $ math_3 = new Math (); $ math_4 = new Math (); echo" Objects created: ". Math :: getCount (); echo"
"; echo" Objects created: ". $ math_4-> getCounter ();?>

In this example, we added the usual $ counter property to the class, it also increased by one in the constructor. But the normal property belongs to the object, so it doesn't persist between calls to objects. At any creation of an instance of a class (object), the property will be equal to zero, in the constructor it will be increased by one.

A static property belongs to the class, so its value is preserved.

Below are a few more examples that show how static properties and methods work.

Attempting to use the $ this variable in a static method will result in an error (Fatal error: Using $ this when not in object context).

PHP static methods age. "old."; // this is an error "Using $ this when not in object context". )) $ TestClass = new TestClass (); $ TestClass-> sayHello (); ?>

By the way, without the line:

$ TestClass-> sayHello ();

there will be no error, but as soon as you try to run a static method with the $ this variable in your code, you will immediately receive an error message.

If you remove the word static in this example, then there will be no error.

If you refer to a property of an object from a static method, it will lead to an error. You can only access static properties using the self :: $ age construct. Note that there is a $ sign in front of the variable name, as opposed to the $ this-> age construct.

PHP static methods sayHello (); ?>

Removing the word static in front of the property name in this example results in an "Access to undeclared static property" error.

There are no static properties in class objects.

PHP static methods "; print_r ($ TestClass); echo""; ?>

A static method can be called using the self :: method () construction. Example:

PHP static methods printHello (); ?>

A static property can be obtained in the context of a class using the syntax:

echo TestClass :: $ age;

Moreover, an attempt to access an ordinary property in this way will result in an error: "Fatal error: Access to undeclared static property".

A static property can be changed in the context of a class using the syntax:

TestClass :: $ age + = 20; // eg

Another example of code with static methods and properties

In this example, there are some more simple options for using static methods and properties. The more simple code you understand, the better you will remember the material.

PHP static methods ".TestClass :: $ age; // echo TestClass :: $ txt; // Error: Fatal error: Access to undeclared static property. Echo"
"; TestClass :: sayHi (); echo"
"; TestClass :: sayHello (); // And this is how I got access to a static variable through an object ($ obj :: $ age) ... echo"
"; $ obj = new TestClass; echo" Getting access to a static variable through an object: ". $ obj :: $ age;?>

Note, and this is important, in this example we have addressed the non-static sayHi () method using the syntax for calling static class members.

Summary

  • The main point is that static properties belong to classes, not objects.
  • You cannot access ordinary properties and methods of a class from a static method, $ this-> name does not work here.
  • From a static method, you can refer to static properties using self :: $ name.
  • Class static properties are not available to objects.
  • A regular method can access a static property using self :: $ name.
  • A static property can be obtained in the context of a class using the syntax: TestClass :: $ age.
  • A regular method can be called in the context of both an object ($ object-> method ()) and a class using the syntax TestClass :: method ().
  • Using the syntax $ object :: $ age, I was able to access a static property through an object.

Parallels with JavaScript

JavaScript has such a class called Math, which contains many different mathematical functions.

To perform mathematical calculations (calculating the sine or exponent) in JavaScript, you do not need to create an object of the Math class, since its methods are static. Before learning PHP, I could not understand what it was in any way, and only after studying classes and objects in PHP in my head everything fell into place.

In fact, it is very convenient to have direct access to the mathematical methods of the Math class, avoiding creating an object.

(Late Static Binding, LSB) has been a hot topic for the last three years in PHP development circles (and finally we got it in PHP 5.3). But why is it needed? In this article, it will just be considered how late static linking can greatly simplify your code.

At the PHP Developers Meeting in Paris in November 2005, the topic of late static linking was formally discussed by the core development team. They agreed to implement it, along with many other topics that were on the agenda. The details were to be agreed upon through open discussions.

Since late static linking was announced as an upcoming feature, two years later. Finally, LSB became available for use in PHP 5.3. But this event passed unnoticed for developers using PHP, from the notes only a page in the manual.

In short, the new functionality of late static binding allows objects to still inherit methods from their parent classes, but in addition to this, it allows inherited methods to have access to static constants, methods and properties of the descendant class, and not just the parent class. Let's take an example:

Class Beer (const NAME = "Beer!"; Public function getName () (return self :: NAME;)) class Ale extends Beer (const NAME = "Ale!";) $ BeerDrink = new Beer; $ aleDrink = new Ale; echo "Beer is:". $ beerDrink-> getName (). "\ n"; echo "Ale is:". $ aleDrink-> getName (). "\ n";

This code will give this output:

Beer is: Beer! Ale is: Beer!

Class Ale inherited method getName () but at the same time self still points to the class in which it is used (in this case, it is the class Beer). This remained in PHP 5.3, but the word was added static... Let's look at an example again:

Class Beer (const NAME = "Beer!"; Public function getName () (return self :: NAME;) public function getStaticName () (return static :: NAME;)) class Ale extends Beer (const NAME = "Ale!" ;) $ beerDrink = new Beer; $ aleDrink = new Ale; echo "Beer is:". $ beerDrink-> getName (). "\ n"; echo "Ale is:". $ aleDrink-> getName (). "\ n"; echo "Beer is actually:". $ beerDrink-> getStaticName (). "\ n"; echo "Ale is actually:". $ aleDrink-> getStaticName (). "\ n";

New keyword static indicates that it is necessary to use the constant of the inherited class, instead of the constant that was defined in the class where the method is declared getStaticName ()... Word static was added to implement new functionality, and for backward compatibility self works the same as in previous versions of PHP.

Internally, the main difference (and, in fact, the reason why the binding was called late) between these two access methods is that PHP will define a value for self :: NAME during "compilation" (when PHP symbols are converted to machine code that will be processed by the Zend engine), and for static :: NAME the value will be determined at startup (at the moment when the native code is executed in the Zend engine).

This is another tool for PHP developers. In the second part, we will look at how it can be used for good.