class MyClass // C++ like comments are supported{}Ring a bell? C++ would complain about the missing semi-colon, but never mind. Good, we have a class; let us now unfold it while pointing out differences and similarities as we go along. Most differences are merely syntactical, and only a few go deeper.To keep things simple, we will restrict our analysis to PHP4.
// Notice "extends" keyword. All inheritance is public anyway. class MyClass extends BaseClass{ var $_dow; // For some historical reasons class var $_ray; // attributes are declared with "var" var $_me; // keyword (ours is not to reason why) // Constructor, like in C++ is a function named like class // "function" keyword is mandatory. No return type. function MyClass($param) { // Explicit call to parent class constructor $this->BaseClass($param); } // There is no ~MyClass() // Return types are not specified, reference (&) is. function & get_note($note) { // We assume $note is a string (could check with is_string()) switch ($note) // Highly familiar switch statement... { case 'dow': // ... apart from its understanding strings ! return $this->_dow; case 'ray': return $this->_ray; case 'me': return $this->_me;_me; default: break; } // Undefined return values are your responsibility ! }}At first, syntactical differences may be irritating, but that will soon fade. You have to remember that PHP is interpreted, so if the "$" prefix makes variable lookup faster or $this-> is necessary to disambiguate between local/global scope and class member, it is still a small price to pay and does not introduce conceptual differences with regard to C++. A bigger difference is the lack of a destructor. This issue is common to all garbage-collected languages. As far as the programmer knows, object destruction is not deterministic, so you have to release whatever resources you owe to the system in an explicit manner. Unlike in C++, you cannot rely on the destructor to "remember" to clean up after you. Since you seldom own system resources (even database connections are released at the end of the HTTP request), it is not a big issue.The constructor is pretty much the same as in C++, except for the absence of automatically nested calls to the base class constructor. In other words, you must call the base class constructor explicitly. So the first thing to do when writing a derived class is to write the $this->BaseClass(); statement before you forget (and before it comes back to haunt you).Let us look at the switch before we leave low-level concerns that are more reminiscent of C than of C++: PHP accepts strings as switch argument whereas the C switch only accepts native types—integer or pointer. A rather nice change, really.So Object is Possible...If You are CarefulThe longer I have been acquainted with PHP, the more I have come to realize that—even though it differs from C++ by hundreds of details—there is no conceptual gap between the two languages such as would render good practices honed by years of C++ inoperative.One must remember that object support came as an afterthought to PHP (the story goes that it was added during one night by Zeev Suraski and Andy Gutmans), so its implementation is not foolproof and will let you do things that will result in loss of sleep.On the other hand, your C++ training has provided you with the one thing that will help you avoid object PHP booby traps. C/C++ has taught you to think like a compiler, feel what must be going on in the memory, decipher cryptic error messages, and guess the compromises made by language designers—keeping in mind, of course, that under the hood PHP is all made of C.So one sure thing is that the deeper your understanding of C++, the easier it will be for you to use PHP à la C++.Navigating Uncharted Waters SafelyObject methodology encourages systematic practices. Some aspects of PHP are confusing and don't lend themselves well to object treatment. For instance, in PHP4 object assignment (operator =) copies the object to the left-hand value. The depth of shallowness of that copy is never clear and is usually irrelevant to the problem at hand. Just avoid the problem by making systematic use of references:
$objref=&$obj;Unless you explicitly intend to clone an object, copying usually reveals a design flaw in your program and results in two (or more!) objects with more or less consistent states while they're supposed to stand for the same piece of data. This is an all-too-frequent waste of memory and a source of confusion. Just avoid it—until PHP5!Here again your C++ background should come to the rescue. Copy constructor annoyances must have taught you to keep things as simple as possible.I miss my templates and pointers to functions.I happen to be obsessively attracted by generics. Time is better invested in identifying and solving a category of problems once and for all than in writing nearly the same piece of code over and over. A wonderful, albeit sometimes arcane, feature of C++ is templates. Once you have realized how much work you may extract from the compiler by a judicious use of templates, it is difficult not to get addicted to them. In consequence, it makes adopting a language devoid of generics much less appealing.In fact, it is quite easy to use generics with PHP, using callbacks or code generation.Explaining the latter would require a full article or a book. Let us just mention that it can be easily implemented with PHP/XML technology.PHP callbacks are the conceptual equivalent of C pointers to functions. Whatever the language, they are to programming what verbs are to speech (variables being the equivalent of nouns, of course). The textbook example is enumeration: let us say you want to list a set of orders. The presentation code is not aware of whether data comes from flat files, XML, or a SQL query. All it has to do is call the enumerator, passing it a callback to handle resulting calls:
/*** Process one order independently of data source** @param $order_data mixed Whatever data is* @return boolean true if OK or false*/function print_order($order_data){ // Process order data (output one record for instance) echo ('<tr><td>'.$order_data.'</td></tr>'); return true;}/*** Enumerates order records through callback** @param $caller string Name of callback.*/function enum_orders($callback){ while (/* whatever it takes to retrieve one order */) { // Here's one record, handling is up to caller. if (!call_user_func($callback,$order_data)) { break; } }}// Now let's use it<?php enum_orders('print_order'); ?>Now, we may want to mail the very same orders instead of just printing them. We simply need to change the callback to, say:
<?php enum_orders('mail_order'); ?>OK, this is simplistic and we could do much better (invoke one object's method). The point is that callbacks are available, as in C++ (their consisting in a string rather than a pointer is immaterial as far as design is concerned).Callbacks are nice, but still they are a bit old hat, they're SDK-like, and they don't take much advantage of object capabilities. We can take them one step further and regroup them into interfaces. This calls for abstract classes. PHP does support this feature:
// C++class IMyInterface{public: // Virtual methods declared with "=0" are abstract virtual void fun1(int nParam) = 0; virtual void fun2(long lParam) = 0;}// PHPclass IMyInterface{ // Methods declared with "{}" are abstract function fun1($nParam) {} function fun2($lParam) {}}Your interface defines a "contract" that you or someone else will fulfill by implementing the abstract class. The nice thing is that implementations will be replaceable like spare parts are—software components.When application logic starts scaling up (as it always does in the end), this style of programming can make the difference between rampaging complexity and continued control of a linear evolution.The next logical step is to use a class factory, but it would take us much further than intended.Now if, as I hope, reading these lines has whetted your appetite for object PHP, do visit www.reflexivecms.org. The XML/PHP framework that lives there goes one step further and beyond.Quick Comparative StudyThese cousin languages bear a strong resemblance as well as clearly distinctive traits:
C++ | PHP | |
Class | Class MyClass : public BaseClass {} | class Class MyClass extends BaseClass {} |
Inheritance | Multiple | Simple |
Constructor | MyClass() {} | function MyClass() {} |
Destructor | ˜MyClass() {} | None |
Parameter Passing | By value but widespread use of pointers make it equivalent to references (references are also supported). | Passing objects by value by default has been making PHP the odd language out. PHP 5 will bring it in line with other object languages. |
-> operator | Pointer to class or struct member. | Access to class member (would be "dot" in many languages, but dot is already string concatenation operator). Pointers are absent in PHP. |
f()->g() calls | Can be arbitrarily nested. | Will be supported by PHP 5. Until then use saved returned value (a two-steps process) $r=&f(); // step 1 $r->g(); // step 2 |
Type system | Statically typed. | Dynamically typed. |
Strings | Not a native type (ASCIIZ). | Natively supported. |
Arrays | Static | Dynamic— - Associative |
Garbage collector | None, ; manage memory the hard way. | All system resources are garbage garbage-collected. |
Preprocessor | Very elaborate. | Absent—define() supported. |
Language level | L3G with L4G-like libraries. | L4G, sometimes strongly reminiscent of L3G. |
Philippe Lachaise (plachaise@virtualmice.net) started with IT in the mainframe environment of the mid-80s. Moving to specialized translation of computer software, he started programming seriously to build translation productivity tools. An early adopter of object technology, he has since had experience with various flavors of object application development. Now Lachaise learns and practices Web standards. To reconcile time-honored object development practices with Web constraints, he has recently been developing RefleXiveCMS, an XML/PHP application framework that aims at transposing to Web development more than ten years of C++ and componentware experience.