Disadvantages of static methods in PHP

In the theoretical database access class, I found that the class uses quite a few helper functions that have nothing to do with the class instance (and others that could be manipulated so as not to relate to the class instance using dependency injection).

For example, I have a function that gets a string between two other lines in a variable. I was thinking of moving this to the String_Helper class or something like that. This function has already been made static.

In addition, I have a function that queries the database, query($sql) . Connection details are provided by the instance, but I considered the possibility of its staticness using query($sql, $connection) . Then the developers will be able to call it statically and should not create an instance of the database class at all.

For me, the following questions:

  • Should I do something like this? Functions such as the query function make me wonder if I'm not just trying to make everything as static as possible, without any real need. Under what circumstances do you find this useful?

  • I know that static functions are harder to test, but if I make sure their code is completely dependency-free (or if it uses dependency injection if necessary), then they are as easy to test as anything else, of course

  • This is not a problem at the moment, but if in the future I decided to extend classes with static functions, it would be impossible for me to force the current code to use my advanced functions. I was thinking about Singletons, but the same problem occurs: the code will call Singleton_Class::getInstance() , not My_Extended_Singleton_Class::getInstance() . Dependency injection seems to be the only way to solve this problem, but it can lead to a clunkier API, since each dependency must be assigned to an object on __construct() .

  • I have a container class that puts certain pieces of information statically so that they can be accessed anywhere in the script (global scope). If I cannot use static functions or singletones, the class containing instances of different variables will be large. For example, you can use Container::$objects['MyClass'] = $MyClass_object; and then the rest of the code could just access Container::$objects['MyClass'] . If I extended the MyClass class, I could use Container::$objects['MyClass'] = $MyExtendedClass_object; and the code that used Container::$objects['MyClass'] will use MyExtendedClass, not MyClass. This is by far the best way to do this, in my opinion, but I would like to know what you think about it.

+7
source share
1 answer

Ok, let me answer this one by one ...

1. Is it worth doing something like this

Yes and no. A good idea is to split the helper functions into your own classes. It keeps the "sphere" of each class rigidly defined, and you do not get hacked. However, do not set the method static just because you can. The request method is to simplify your life by managing the connection, so why do you want to lose this benefit?

2. They are harder to test

They are not harder to verify. State-dependent static methods are harder to test (to access static member variables or global variables). But static methods in general are as easy to test as instance methods (in fact, they can be simpler, since you don't have to worry about importing).

3. Extension of classes

This is an urgent problem. If you put String_Helper::foo() in the class itself, you will run into problems. But an option would be to set the name of the string helper as a class variable. That way you could do {$this->stringHelper}::foo() (note only PHP 5.3). Thus, to override a class, all you have to do is change the class of auxiliary rows in this instance. The Lithium structure makes this a lot ...

4. Global registry

I would stay away from this. You basically just make each class a singleton without using it. Testing will be a nightmare, because now you are dependent on a global scale. Instead, I would create a registry object and pass it to classes through the constructor (Dependency Injection). You do the same thing anyway, since you have storage for objects / classes, but you are no longer dependent on the global scope. This greatly simplifies testing.

Usually

When you look at such things, I like to stop when I come across such questions. Stop, sit down and think: "What is the actual problem I'm trying to solve?". List the problem explicitly. Then pull out our proposed solutions and see if they really solve them. If so, think about the future and if these solutions are indeed supported in the long run (both from the point of view of fixing errors, and taking into account additions to functions). Only if you are happy with both of these answers should you think about it. Oh, and don’t forget, Programming is not about making the hardest, smartest or most amazing decision. It's about making the simplest solution that solves the problem ...

I hope this helps ...

Good luck

+9
source

All Articles