Re: defining a global object table
| From: | J. Adams | Date: | Tue, 08 Nov 2011 23:46:50 +0000 |
| Subject: | Re: defining a global object table | ||
| References: | 1 2 | Groups: | php.pecl.dev |
| Request: | Send a blank email to pecl-dev+get-8839@lists.php.net to get a copy of this message | ||
Thank you, Johannes, for the your response. I'm really grateful to have access to the guys who know the ins and outs here.
I'm having some difficulty understanding how your example necessitates the php_add_var_hash approach in var.d that you have recommended. I appreciate you pointing out situations that will result in weird behavior and I believe the example you provided could cause a problem because code execution switches back and forth between PHP and C execution. From your example:
<?php
serialize($data);
?>
This results in the traditional serialize function (implemented in C) being called on the array, $data. When the recursive serialization logic reaches $data[0], with a member var pointing to an instance of class A, control is handed to the method A::serialize (defined in PHP) which in turn calls some serialization function (base64_encode, serialize, amf_encode, whatever). Because of the transfer of execution from PHP to C and back to PHP and back to C, the original object might be serialized separately as distinct copies rather than with proper object references.
If I'm not mistaken, the approach I suggested will avoid infinite recursion by recognizing that a prior object has been encountered based on its memory address. If a weird scheme results as you have suggested and this results in copies being created in the results when we unserialize, I think that may not be all that bad -- I aim only to reproduce the behavior of AMF3 serialization exhibited by Flash Player. I'll have to see if there's some equivalent behavior in Flash Player.
If there is some other advantage or pitfall that I'm missing, please point it out. I'd like to point out that PHP serialization doesn't really handle this situation properly either. Try running this script:
<?php
class A implements Serializable {
public $p;
public function serialize() {
return base64_encode(serialize($this->p));
}
public function unserialize($data) {
$this->p = base64_decode(unserialize($data));
}
}
$data = array(new stdclass(), new A());
$data[1]->p = $data[0];
echo "here is \$data\n";
var_dump($data);
$s = serialize($data);
echo "\nhere it is serialized:\n$s\n";
$d = unserialize($s);
echo "\nhere it is unserialized again\n";
var_dump($d);
?>
The serialization both results in a serialization error and the unserialized object is not the same as the serialized one:
here is $data
array(2) {
[0]=>
object(stdClass)#1 (0) {
}
[1]=>
object(A)#2 (1) {
["p"]=>
object(stdClass)#1 (0) {
}
}
}
here it is serialized:
a:2:{i:0;O:8:"stdClass":0:{}i:1;C:1:"A":28:{Tzo4OiJzdGRDbGFzcyI6MDp7fQ==}}
PHP Notice: unserialize(): Error at offset 0 of 28 bytes in /var/www/amf/index.php on line 9
PHP Stack trace:
PHP 1. {main}() /var/www/amf/index.php:0
PHP 2. unserialize() /var/www/amf/index.php:21
PHP 3. A->unserialize() /var/www/amf/index.php:0
PHP 4. unserialize() /var/www/amf/index.php:9
here it is unserialized again
array(2) {
[0]=>
object(stdClass)#3 (0) {
}
[1]=>
object(A)#4 (1) {
["p"]=>
string(0) ""
}
}
On 11/7/2011 1:36 PM, Johannes Schlüter wrote:
Hi, I didn't think completely through your mail, but I think you want to look at PHP's serializer, especially php_add_var_hash() and its usage. On Sun, 2011-11-06 at 17:14 -0800, j adams wrote:ZEND_BEGIN_MODULE_GLOBALS(amf) zval **objects_and_arrays; // array containing memory addresses of arrays and objects encountered int objects_and_arrays_count; // number of serialized arrays/objects stored in the array int objects_and_arrays_allocated; // number of slots allocated for the array ZEND_END_MODULE_GLOBALS(amf)Don't use globals for that. You might have stuff like "nested serialisation", again using php serialisation as example with a non-sense but possible example: <?php class A implements Serializable {public $p;public function serialize() { return base64_encode(serialize($this->p)); } public function unserialize($data) { $this->p = base64_decode(unserialize($data); }} $data = array(new stdclass(), new A()); $data[1]->p = $data[0]; serialize($data); ?> In this case a second independent serialisation is started while the first one is still running, the global variable therefore would be poluted. Better is to pass the "var_hash" (as it is called in PHP's serializer as mentioned above) as parameter. johannes