A detailed explanation of original sin based on PHP static class

  • 2020-06-01 08:59:03
  • OfStack

Hegel famously said, "to be is to be reasonable." With this as an argument, the use of static classes must be reasonable. However, when things go too far, the code becomes too dependent on static classes, and its deterioration is inevitable. This is like the poppy as a herb, has its pharmacological value, but if used recklessly in large quantities, it becomes a drug.

What is a static class

A static class is a class that is called statically without having to instantiate an object. The code is as follows:


<?php
class Math
{
    public static function ceil($value)
    {
        return ceil($value);
    }
    public static function floor($value)
    {
        return floor($value);
    }
}
?>

The role of the class is more like a namespace, which is probably the most direct reason why many people prefer to use static classes.

Problems with static classes

Essence, static class is process oriented, because usually it is only the mechanical switch process oriented code set to 1, while in class's form is the result, but this time the class is more like a 1 piece of the emperor's new clothes, so a static class is, in fact, covered with object-oriented shell, doing the process oriented.

Object-oriented design principle 1: program to the interface, not to the implementation. What difference does it make? For example, regardless of price, would you prefer a PC with a standalone video card or one with an integrated video card? I think the vast majority of people would choose a separate video card. Separate graphics CARDS can be thought of as programming to the interface, and integrated graphics CARDS can be thought of as programming to the implementation. So the downside of implementing programming is clear: it loses the possibility of change.

Make up an example of an article management system to illustrate 1 below:


<?php
class Article
{
    public function save()
    {
        ArticleDAO::save();
    }
}
?>

Article implement the necessary business logic, and then give ArticleDAO data persistence to do it, and ArticleDAO is a static class, as if the welding on the motherboard integrated graphics 1 sample is difficult to change, suppose that we may need to test the code Mock ArticleDAO implementations, but because the call is used in the name of the static class, is equal to have binding concrete implementation approach, Mock almost impossible, of course, there are actually some ways to achieve:

<?php
class Article
{
    private static $dao = 'ArticleDAO';
    public static funciton setDao($dao)
    {
        self::$dao = $dao;
    }
    public static function save()
    {
        $dao = self::$dao;
        $dao::save();
    }
}
?>

With the intervention of variables, you can specify which static class to use at runtime:

<?php
Article::setDao('MockArticleDAO');
Article::save();
?>

Although this implementation seems to solve the problem of Mock, first of all, it modifies the original code, which violates the open and close principle. Second, it introduces static variables, which are the Shared state and may interfere with the execution of other codes. Therefore, it is not a perfect solution.

As a side note, it is possible to implement Mock simply by means of require1 different class definition files with dynamic language features. However, this has its own disadvantages. It is assumed that we need to change the implementation method many times in the script, but in fact we only have one chance of require.


Object value

If you give up static classes and use objects instead, how do you implement the article management system example? The code is as follows:


<?php
class Article
{
    private $dao;
    public function __construct($dao = null)
    {
        if ($dao === null) {
            $dao = new ArticleDAO();
        }
        $this->setDao($dao);
    }
    public function setDao($dao)
    {
        $this->dao = $dao;
    }
    public function save()
    {
        $this->dao->save();
    }
}
?>

In fact, this is where the commonly used dependency injection technique is used to inject dependent objects through constructors or Setter:

<?php
$article = new Article(new MockArticleDAO());
$article->save();
?>

Objects have their own state and no Shared state interferes with the execution of other code.

...

Of course, there is a good side to static classes, such as a good way to implement some stateless utility classes, but most of the time, my subjective inclination is very clear, more objects, less static classes, to avoid premature solidification of the system. By the way, I hope no one told me about the static object analogy or something like that. Thank you.


Related articles: