新对象模型

PHP 5 中有个新对象模型(Object Model)。PHP 处理对象的方式完全重写了,允许更佳性能和更多特性。之前版本的 PHP,对象处理方式和原始类型(例如整型和字符串)相同。此方法的缺点是当变量被赋值或作为参数传递给方法时语义上整个对象都被拷贝。在新方法中,对象通过句柄引用,而不是值(可以将句柄当成是对象的标识符)。

很多 PHP 程序员根本没意识到旧的对象模型的这种拷贝怪癖,因此大多数 PHP 应用程序拿来就能运行,或者只做很小的修改。

新对象模型的文档见语言参考

与 PHP 4 的兼容性参见 zend.ze1_compatibility_mode


add a note add a note User Contributed Notes
quinn at strangecode dot com
19-May-2006 11:53
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.
riseofthethorax at yahooo dot com
29-Sep-2005 09:53
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
hairmare-spam at purplehaze dot ch
10-Jun-2005 07:41
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.
ivanildo at kowsoleea.de
23-May-2005 05:56
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.