Delicious Bookmark this on Delicious Share on Facebook SlashdotSlashdot It! Digg! Digg



PHP : Appendices : Migrating from PHP 4 to PHP 5 : New Object Model

New Object Model

In PHP 5 there is a new Object Model. PHP's handling of objects has been completely rewritten, allowing for better performance and more features. In previous versions of PHP, objects were handled like primitive types (for instance integers and strings). The drawback of this method was that semantically the whole object was copied when a variable was assigned, or passed as a parameter to a method. In the new approach, objects are referenced by handle, and not by value (one can think of a handle as an object's identifier).

Many PHP programmers aren't even aware of the copying quirks of the old object model and, therefore, the majority of PHP applications will work out of the box, or with very few modifications.

The new Object Model is documented at the Language Reference.

In PHP 5, function with the name of a class is called as a constructor only if defined in the same class. In PHP 4, it is called also if defined in the parent class.

See also the zend.ze1_compatibility_mode directive for compatability with PHP 4.

Code Examples / Notes » migration5.oop

zzo38

You should be able to clone a object in compatibility of PHP4,PHP5 with:
<?php
$x=unserialize(serialize($y));
?>


bdas

Since PHP5 upgraded PHP to an OOP language, they CHANGED the metaphor so that when you copy an object, you just get a pointer to it (as in C# and Java) and so therefore they needed to make a way to CLONE objects as well in case you need a REAL copy of the object.
Most cases, clone is not needed, simply because a real copy of an object is usually not mandatory.  In special cases, object cloning can be used to save time in porting.


ivanildo

It seems that simpleXML functions like 'simplexml_load_file' do not work in ze1 compatibility mode due to some cloning 'features' I do not yet understand.

hairmare-spam

I have noted some discussion going on about the 'Cannot re-assign $this' error.
The most simple way to reproduce the error is:
class MyObject
{
       function test()
       {
               $this = new MyObject;
       }
}
I found the following quote (quoting zend.com) on php-dev:
 http://www.zend.com/php/ask_experts.php :
 "The fact that you could change in PHP 4, was never really meant to be
 although it worked. In PHP 5 we removed this option due to performance
 and semantic reasons. In PHP 5, you can either use a factory method
 pattern or throw an exception on error in the constructor."
This statement implies that the error lies not in PHP5 but in the script. A Bogus Bug in http://bugs.php.net/bug.php?id=27659 tells me the same thing.
There has been some discussion on how to migrate such code to php5 without having to reengineer the whole App. From my point of view the following solutions are viable:
1. Use delegation & Object composition:
$this->Object = new Whatever();
function nameOfFunction()
{
    return $this->Object->nameOfFunction();
}
This requires lots of code rewriting. Some of it could be realised with overloading. Variables would need to get overloaded or could only be accessed using a getter/setter. As a xtra you get clean OO Code!
2. Replace Original Objects Content:
foreach (get_object_vars($foo) as $key => $value)
 $this->$key = $value;
This solution only works with instance-variables. Additional classkit/runkit code would be needed to get everything else correct. This way less refactoring would be needed. This could be the right way to go if you don't need to replace any methods or the classname.
I haven't decided wich way to go. I wrote this so the next hacker with this problem finds some info where I was looking for it.


riseofthethorax

I actually understand the addressing modes in 4.3 and use them, it hasn't bothered me.. Like I have objects within objects, each with variables containing references (like pointers but without the pointer arithmetic).  I can obtain an object group from the database, obtain the method interface to a subobject, issue a manipulation through the child, then store the object group back into the database with the manipulation intact.. I'm not sure what effect the new changes will have on this, but if its drastic, I'm not sure I can support 5.0.
A nice little userlevel way of messing with PHP's addressing,
the use of aliases:
// I haven't coded in PHP for a while so sue me
class stuff {
  var $stuff;
  function stuffer() {
     $null = NULL;
     $s = &$this->stuff;
     $s = "some stuff";
     $s = &$null;
  }
}
This works.. You can make some assumptions about
what is going on behind the scenes, especially
what $s is before being assigned a reference to
another variable and after.. Its either two kinds of things,
a reference to a variable or a container of data, or
its a reference to a data location at all times, just that by default it gets an address to a string and at other times it can be assigned the address of objects. The "&" redirects where its pointing. At least this is how I think about it.
I use this side-effect all the time for making aliases in my objects..
Kiernan


quinn

Here is another possible solution for migrating code to php 5 when using $this = 'something' reassignments. In my case, I had several classes  with methods that were self-instantiating with static calls. I was able to simply use a different variable: I changed $this to $_this and it worked the same because I copied an instance of the original object by reference using an instantiation factory method:
class DB {
   function &getInstance()
   {
       static $instance = null;
       if ($instance === null) {
           $instance = new DB();
       }
       return $instance;
   }
   ...
In every method needing access to this object I assigned it to a temporary variable by reference:
   
   function doSomething ()
   {
       $_this =& DB::getInstance();
       $_this->doSomethingElse();
       $_this->param['id'] = 123;
   }
Which allows method calls or saving data back to the original object.
I originally created classes like this so I didn't need to keep track of instantiations or global objects. I could just call DB::doSomething() and the object is created dynamically or referenced from an already existing object.


Change Language


Follow Navioo On Twitter
What has changed in PHP 5
Backward Incompatible Changes
CLI and CGI
Migrating Configuration Files
New Functions
New Directives
Databases
New Object Model
Error Reporting
eXTReMe Tracker