‘clone’ for PHP4

Steven Wittens from Acko.net describes a way of implementing a clone function in PHP4 to emulate PHP5’s clone behaviour.

The idea is to write object-oriented programs that will behave the same way in both PHP4 and PHP5. Obviously, the drawback of doing so is that you cannot take advantage of PHP5-only features, such as object destructor methods. But if you accept the limitations, you can still write code for PHP4 that works on PHP5, but there are a few important snags. PHP5’s treatment of objects and references is one of those snags.

In PHP4, you can create a copy of an object using the equals (=) operator alone. However, in PHP5 this will create another reference to the same object (much like Java). PHP5 defines the clone keyword, which can be used to create a separate copy of an object.

PHP5’s clone is, strictly speaking, not a function. It is a language construct, and (in common with some other language constructs such as exit and include) it can be used either with or without parentheses. If we’re going to emulate it in PHP using a function, we will always need to use it with parentheses.

Steven’s method defines “clone” as a function when using PHP4, but still allows PHP5’s built in clone to be used when running in PHP5.

A weakness in his method is its dependance on eval, which I consider to be an inelegant solution (see Lachlan’s rant about eval). Here, eval is used to prevent the function from being defined when using PHP5 (it is a reserved word in PHP5).

If you really don’t care for eval, a possible solution would be to use a conditional include. Place the function definition for clone in a separate file, php4.inc.php, and include that file only when PHP5 is not being used.

The following code, therefore, should provide a PHP4 emulation of PHP5’s clone without using eval:

php4.inc.php


// Define a PHP4 emulation of PHP5's clone
function clone($object)
{
return $object;
}

Your application:


if (version_compare(phpversion(), '5.0') < 0)
{
include 'php4.inc.php';
}

// For example, we can create an object
$object = &new object();

// Clone it!
$myclone = clone($object);

What if you don't want to clone an object? If you've done any OOP in PHP4, then you will be familiar with the use of the reference operator & to pass a reference to an object. The good news is that in PHP5, this will continue to work.

On another note, we've had a lot of feedback from you on what's keeping you from moving completely to PHP5. Various issues include web hosts not wanting to make the move, the break in compatibility (particularly the clone issue discussed in this article), and stability issues, while other users report that they are happily using PHP5 exclusively and haven't looked back.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Nico Edtinger

    In this case eval() can be used without any problems. No variables are inserted in the evaled string. And to the Zend Engine include and eval is the same, but including needs more file operations. Thus the version with eval() is already the optimized version.

    b4n

  • topsmith

    __clone() IS EVIL!!!

  • http://www.phpism.net Maarten Manders

    That’s the ‘smarter idea’ I was talking about in the eval() discussion. One could define the whole function in an if-block as well but that’s more of a hack.

  • http://blog.phpdoc.info/ scoates

    eval/include isn’t necessary, just use a conditional function declaration:


    php -r "if (FALSE) { function moo() { } } var_dump(function_exists('moo'));"
    bool(false)

    S

  • Lachlan

    As mentioned in the original article, the problem is that clone is a special keyword in php4. What this means is that PHP will fail with an error if the clone token exists, even during the parse phase.

  • http://blog.phpdoc.info/ scoates

    In one of my Mail_Mime test casaes, I do precisely this, and it works fine (on both PHP 4 and PHP 5):


    if (version_compare(phpversion(), "5.0.0", '< ')) {
    $mmCopy = $mm;
    } else {
    $mmCopy = clone($mm);
    }

    S

  • Ben

    __clone is actually pretty cool, however, there is an issue with using it with objects with lots of references. even the pear compat clone function does not work if you need to use the __clone function to fix references and re-create objects. This is what needs to happen in PHP4:
    $new_object =& clone($old_object);
    but PHP5 seems to complain with the =& and the clone used together. Also, the pear compat function needs to be modified to return a reference instead of a copy. Basically, there needs to be a php4clone wrapper that will disambiguate all the compatibility issues and then that is what should be used. It won’t be nice PHP5 looking, but it should work.