ÄúµÄλÖãºÑ°ÃÎÍøÊ×Ò³£¾±à³ÌÀÖÔ°£¾PHP ±à³Ì£¾PHP 5 Power programming
Team LiB
Previous Section Next Section

13.5. Other Changes

Although 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 $this

When 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:


Fatal error: Cannot re-assign $this in /book/13-making-the-move/oo assign-to-this.php on
 line 11

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_class

Although 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.

    Team LiB
    Previous Section Next Section