The author of the article "The True OO of PHP4"
is Johan Persson, the developer of the famous JpGraph chart class library in PHP. This article is the author's summary of several minor issues that need to be paid attention to when conducting object-oriented development in PHP4.
Translation: Binzy Wu [Mail: Binzy at JustDN dot COM], the level is limited, welcome to discuss. 2004-2-4
Introduction
The target of this article is those who have used more mature OO [ 1] Language, such as Eiffel, Java, C# [2] or C++(), friends who develop (such as myself). There are many semantics when using PHP4 for complete OO development [3] (semantic)
Traps [4].
I hope the content of this article can help others avoid the mistakes I made.
Quotation VS copy semantics
This is basically the main source of errors (at least for me (for example). Even though in the PHP documentation you can read that PHP4 uses copy semantics more than references (like other object-oriented languages that I know of), this will still make you end up troubled by some small details.
The next two parts are used to illustrate two small examples in which copy semantics may surprise you.
It is important to always remember that a variable of a class is not A pointer to a class but the actual class itself [5]. Most problems arise from a misunderstanding of the assignment operator (=), which is thinking that it is giving an alias to an object, when in fact it is making a new copy. For example, suppose $myObj is an instance of a class, and it has a Set() method. Then the following code may not work as a C++ (or Java) programmer expects.
function SomeFunction ($aObj) { $aObj->Set(10); }
…
SomeFunction ($myObj);
…
Now, it’s easy to think The Set() method called by this function will act on $myObj. But this is wrong!
What actually happens is that $myObj is copied into a new, identical copy of the original object---- Parameter $aObj. Then when the Set() method is called, it only acts on the local copy rather than the original parameter----$myObj.
is used where direct or indirect (as above) assignment operations are included. A variety of the above problems can occur.
In order for the function to behave as you expect (probably), then you have to tell PHP to use a reference to pass the object by modifying the method declaration, such as:
Function SomeFunction(&$aObj)
If you try the above code again, then you will find that the Set() method will act on the original parameters, because now we are in action Created an alias of $myObj----$aObj.
But you have to be careful, because even the & operator cannot save you at all times, as in the following example.
Get a reference from a reference
Suppose we have the following code:
$myObject = new SomeClass();$myRefToObject = &$myObject;
If we now Want a copy of the reference (for some reason), so what do we do? You might be tempted to write since $myRefToObject is already a reference:
$myCopyRefToObject = $myRefToObject;
Correct Huh? No! PHP will create a new copy of the object referenced by $myRefToObject. If you want to copy a reference to an object, you have to write:
$myCopyRefToObject = &$myRefToObject;
In a C++ example equivalent to the previous example, a reference to a reference would be created. Unlike in PHP. This is contrary to the intuitive assumption that experienced C++ programmers will often make, and this will be yours. The source of small bugs in PHP programs.
Please be careful about the indirect (passing parameters) or direct problems caused by this.
My personal conclusion is that it is best to avoid these semantics The trick is to always pass objects or object assignments by reference. Not only does this improve runtime (fewer data copies), but it also makes the semantics more predictable for an old dog like me.
Using a reference to $this in the constructor
It is a common pattern to initialize an object as a discoverer of other objects (Observer[6]) in the constructor of an object. The following lines of code will is an example:
class Bettery
{
function Bettery() {…};
function AddObserver($method, &$obj)
{
$this->obs [] = array($obj, &$method)
}
function Notify(){…}
}
class Display
{
function Display(&$batt)
{
$batt->AddObserver("BatteryNotify",$this);
}
function BatteryNotify() {…}
}
However, this will not work properly if you instantiate the object like this:
$myBattery = new Battery();$myDisplay = new Display($myBattery);
The mistake with this is that using $this in the constructor of new will not return the same object. Instead, it will return a copy of the most recently created object. That is, the object passed when calling AddObserver() is not the same as the original object. Then when the Battery class tries to notify all its Observers (by calling their Notify method), it will not call the Display class we created but the class represented by $this (That is, a copy of the Display class we created). So if the Notify() method updates some instance variables, it is not like we imagined that the original Display class will be updated, because what is updated is actually a copy. In order to make it work, you It is necessary to make the constructor return the same object, as originally symbolized by $this. This can be done by adding an & symbol to the Display constructor, such as $myDisplay = & new Display($myBattery);
A direct result is any Clients of the Display class must understand the implementation details of Display. In fact, this creates a potentially controversial issue: all objects must be constructed using the extra ampersand. As I said it is basically safe, but ignoring it may At some point, you will get undesirable effects like the above example.
Another method is used in JpGraph to solve it. That is, you need to use it by adding a reference that can safely use &$this The so-called two-stage construction of the "Init()" method "new" an object (simply because the $this reference in the constructor returns a copy of the object does not work as expected). So the above example would be implemented as follows:
$myBattery = new Battery();
$myDisplay = new Display();
$myDisplay->Init($myBattery);
As in JPGraph.php "LinearScale" class.
Using foreach
Another problem with similar code but different results is the problem of the "foreach" structure. Study the difference between the two loop structures below Version.
// Version 1
foreach( $this->plots as $p )
{
$p->Update();
}
…
// Version 2
for( $i=0; $i
{
$this-> ;plots[$i]->Update();
}
Now the $10 question [7]: Does version1==version2?
The surprising answer is: No! This is a small but crucial difference. In Version 1, the Update() method will operate on a copy of the object in the "plots[]" array. Therefore, the original object in the array will not is updated.
In Version 2 the Update() method will act on objects in the "plots[]" array as expected.
As stated in the first part, this is how PHP will Object instances are treated as objects themselves rather than as the result of object references.
Annotation:
[1]. OO: Object-Oriented, object-oriented.
[2]. The original text does not have C# , all due to Binzy's personal hobbies.
[3]. Semantic is translated as "semantics" in this article. If you have any suggestions, please contact Binzy.
[4]. There is a famous "C++" book in C++ Gotchas".
[5]. The class here should refer to Instance, that is, instance.
[6]. See "[GoF95]", that is, "Design Patterns".
[7]. Yes A very interesting little story about trading:
Someone bought a horse for $60 and sold it for $70; then, he bought it back for $80, and finally sold it for $90. Sell at the price. In this horse trade, he? (A) lost $10; (B) broke even; © made $10; (D) made $20; (E) made $30 .
This is a simple arithmetic problem that psychologists Meyer and Burke of the University of Michigan asked college students to calculate. As a result, less than 40% of college students were able to give the correct answer, and most people thought they only earned 10 U.S. dollars. In fact, the conditions of the problem are very clear. These are two transactions, each time making a profit of 10 U.S. dollars, but many people mistakenly believe that when they bought it back with 80 U.S. dollars, they lost 10 U.S. dollars. Interestingly, the same The question is posed in another way: A person bought a white horse for $60 and sold it for $70; then, he bought a dark horse for $80 and sold it for $90. Go. In this horse-trading transaction, he ____ (list the same five choices). At this time, when another group of college students answered the above questions, everyone got the answer correct.