|
13.5. Other ChangesAlthough the compatibility mode covers a few changes between PHP 4 and PHP 5, it does not fix all possible changes. For example, PHP 5 does not allow assigning to $this, which is a problem for a few PEAR classes (at the time of this writing). For example, the Pager/Pager.php file has the following code in its constructor: $mode = (isset($options['mode']) ? $options['mode'] : 'Jumping'); $pager_class = 'Pager_' . ucfirst($mode); $pager_classfile = 'Pager' . DIRECTORY_SEPARATOR . $mode . '.php'; require_once $pager_classfile; $this = new $pager_class($options); Another PHP 5 change not reverted by compatibility mode is the behavior of get_class(). 13.5.1. Assigning to $thisWhen you use a line in PHP 4 that assigns a value to $this inside a class, depending on an option, a class is selected and an instance to that newly created class is returned. Simplified, the code looks like this (with the offending line in bold): <?php class Jumping { } class Sliding { } class Pager { function Pager($type) { $this = new $type; } } $pager = new Pager('Jumping'); ?> Assigning a new object to $this does not work in PHP 5. When the script runs, it throws the following error:
The only solution for this problem is to redesign the classes. In this case, an alternative that works with both PHP 4 and PHP 5 is <?php class Pager { function Pager($options) { var_dump($options); } } class Jumping extends Pager { function Jumping($options) { Pager::Pager($options); } } class Sliding extends Pager { function Jumping($options) { Pager::Pager($options); } } $pager = new Jumping('foo'); ?> Assigning to $this can also be used to "emulate" an exception, which is necessary because you cannot return errors from a constructor. For example, the Net_Curl PEAR package has the following in its constructor: function Net_Curl() { ... $ch = curl_init(); if (!$ch) { $this = new PEAR_Error("Couldn't initialize a new curl handle"); } ... } This is used to emulate an exception. In PHP 5, the correct way would be to use an . . . exception. For this to work, the PEAR_Error class needs to extend the internal PHP Exception class. In the examples here, we suppose a new PEAR error mechanism with PEAR_Exception is used, but the PEAR project doesn't yet know how they are solving it at the time of writing. The rewritten constructor might look like this: function Net_Curl() { ... $ch = curl_init(); if (!$ch) { throw PEAR_Exception("Couldn't initialize a new curl handle"); } } Besides changing the constructor, code that uses this class needs to be changed to catch the exception too, as in try { $curl = new Net_Curl(); } catch { ... } Unfortunately, this code will not work in PHP 4. You can support both PHP 4 and PHP 5 by using a new approach to the class implementationfor example, with a singleton pattern. An example might be <?php require_once "PEAR.php"; class Net_Curl { var $type; function Net_Curl($type) { $this->__construct($type); } function __construct($type) { $this->type = $type; } function singleton($type) { if ($type == "lala") { return PEAR::raiseError("Unable to do foo."); } else { return new Net_Curl($type); } } } $instance = Net_Curl::singleton("lala"); if (PEAR::isError($instance)) { die("Error: " . $instance->getMessage() . "\n"); } echo $instance->type . "\n"; ?> Tip To find assignments to $this in your own code, you can use the UNIX tool grep: egrep -r '\$this\s+=' * This command finds all instances in this directory and all subdirectories where an assignment to $this is made. 13.5.2. get_classAlthough PHP 4 always returns the class name with lowercased letters, in PHP 5, the get_class() function returns the case-preserved version of the class name: <?php class BookPage { } $page = new BookPage; $name = get_class($page); echo $name, "\n"; ?> The output is bookpage in PHP 4 and BookPage in PHP 5. If you need to rely on the PHP 4 behavior, use the following code instead: $name = strtolower(get_class($page)); echo $name, "\n"; This code works for both PHP 4 and PHP 5. |
|