It is often spread on the Internet that PHP is the one at the bottom of the language contempt chain. I once studied Java in college. , I used Java after graduation, and I just came out to be trained to use Java. During the first 2 or 3 years of working, I had quite a lot of opinions on the object-oriented nature of PHP. I always felt that it was "neither fish nor fowl", let alone my views on JS. However, these views have gradually faded or even changed after experiencing more and more projects. This includes a greater understanding of projects and technologies. At the same time, the Web environment and technologies have been constantly updated over the years. But today I’m not here to talk about these things. Regarding the above issues, my point of view can be summarized as follows: technology is a tool and a means. If it is not suitable, upgrade or replace it. It’s that simple.
Back to the original topic. Although I have been proficient in writing PHP for nearly 8 years, due to work, I often need to involve various codes on the front and back ends, which is easy to separate and always forget. Something happened recently that made me think that maybe writing it down could help me wake up a little bit.
When writing a certain module in a certain year, I used static members. In the process of implementing the subclass, I found that they also shared the value of this member of the parent class. Specifically, I changed that in a certain subclass A. The member value, when used by another subclass B, accidentally gets the value overwritten by A. At that time, I thought that it turns out that static members are shared throughout the category tree starting from the place of declaration. Later, I vaguely remembered this conclusion, and used static members more cautiously in normal code. Unless the class written is confirmed to be an independent tool class, static should not be used easily.
Until one day my boss discussed with me about upgrading a BaseModel I had written before. He accidentally asked me: It seems that you don’t like using static members? I said no, because considering that BaseModel will often be inherited into various Models, if I use static here, it will be easy to get into trouble in the future. He said he didn't understand and then came over to argue with me. I explained righteously that because static members will be shared, if two different subclasses are called, the value of the variable of the static member will be as uncontrollable as a global variable. He disagrees. So in the spirit of science, we wrote a short code to verify:
class A {
protected static $var1 = null;
Public static function test(){
echo get_called_class(). ' '.static::$var1.'
';
}
}
class B extends A {
protected static $var1 = 'b';
}
class C extends A {
protected static $var1 = 'c';
}
B::test();
C::test();
Obviously, I lost this time. The result I expected was c c, but it was actually b c. So it seems that the static members of the subclass are only shared at the subclass level. But I always feel something is wrong. I obviously had another setback when I was writing BaseModel. Why does this verification not support the problems I encountered at that time? Then I realized that I had forgotten something. How nice to be young. Later, when I thought about it, it turned out that the reason why I didn't use static here was just because of design requirements.
I thought I was wrong. Until a few days ago, I wrote a few more parent-child classes (not BaseModel), and boldly used static members. As a result, I stumbled again in the self-test. What's going on! Then I paid careful attention to my usage this time, changed the above example and ran it:
class A {
protected static $var1 = null;
protected static $var2 = null;
public static function test(){
if (! static::$var2) {
static::$var2 = static::$var1;
}
echo get_called_class(). ' '.static::$var1.'
';
}
}
class B extends A {
protected static $var1 = 'b';
}
class C extends A {
protected static $var1 = 'c';
}
B::test();
C::test();
The result is
B b
C b
If the conclusion last time was correct, how do you explain it this time? This clearly means that $var2 is shared by A, B, and C. The difference between $var1 and $var2 seems to be only the difference between declared and undeclared. So I changed it to this:
class A {
protected static $var1 = null;
protected static $var2 = null;
public static function test(){
if (! static::$var2) {
static::$var2 = static::$var1;
}
echo get_called_class(). ' '.static::$var1.'
';
}
}
class B extends A {
protected static $var1 = 'b';
protected static $var2 = null;
}
class C extends A {
protected static $var1 = 'c';
protected static $var2 = null;
}
B::test();
C::test();
The result is
B b
C c
I was shattered inside. So I went to Stack Overflow and found that I wasn't the only one who was wronged.
Only explicitly declared static members will be considered as belonging only to subclasses.
Only explicitly declared static members will be considered as belonging only to subclasses.
Only explicitly declared static members will be considered as belonging only to subclasses.
Say important things three times! However, if there are many subclasses, each member whose value is dynamically determined will be declared in this way, which will lose the meaning of using static in terms of writing code. A better way is to turn $var2 into an array, and put the values to be used by each class in $var[__CLASS__].
But no matter what, if it is not necessary, try not to use static member inheritance.
There is another "pit" that is somewhat similar. When we talk about private members, we all know that private means private and will not be inherited by subclasses. But sometimes I forget when writing code, and I don’t remember until I get started. It turns out that it is private that causes the subclass to not find the members it should have, or that private is declared in the subclass, but because when calling a function, the parent is called. Class function, the result is the private value of the parent class instead of the subclass. In this case, it is impossible to rewrite the function as it is in the subclass. So be very careful when using private.
When I was using Rackspace’s SDK, I saw that some classes used private members, but because they gave unnecessary permissions to open files, the code could not run on our server. So at this time, I wanted to write a subclass to overwrite the initial value of this member, but in the end, because this is a private member, I needed to copy all the references to the subclass I wrote. Why don't we just change the SDK and make the members protected? Because the development package may be upgraded next time? After the correction, we can just remove the subclass. If modifying library code becomes a habit, it won't be so fun when you want to upgrade. Therefore, private members must be used with caution. If you are also developing an SDK, you need to consider whether users need to inherit? If you must write private, can you ensure that the code can be used in various scenarios?
Unless you have a very good reason, both static and private need to be used with caution.