note 125993 added to function.get-object-vars

From: Date: Thu, 08 Apr 2021 22:54:04 +0000
Subject: note 125993 added to function.get-object-vars
Groups: php.notes 
Request: Send a blank email to php-notes+get-216264@lists.php.net to get a copy of this message
When dealing with a very large quantity of objects, it is worth noting that using get_object_vars() may drastically increase memory usage. If instantiated objects only use predefined properties from a class then PHP can use a single hashtable for the class properties, and small memory-efficient arrays for the object properties: If a class is defined with three properties ($foo, $bar, and $baz), "PHP no longer has to store the data in a hashtable, but instead can say that $foo is proprety 0, $bar is proprety 1, $baz is property 2 and then just store the properties in a three-element C array. This means that PHP only needs one hashtable in the class that does the property-name to offset mapping and uses a memory-efficient C-array in the individual objects." However, if you call get_object_vars() on an object like this, then PHP WILL build a hashtable for the individual object. If you have a large quantity of objects, and you call get_object_vars() on all of them, then a hashtable will be built for each object, resulting in a lot more memory usage. This can be seen in this bug report: https://bugs.php.net/bug.php?id=79392 The effects of this can be seen in this example: <?php class Example { public $foo; public $bar; public $baz; } function printMem($label) { $usage = memory_get_usage(); echo sprintf('%s: %d (%.2f MB)', $label, $usage, $usage / 1000000) . PHP_EOL; } printMem('start'); $objects = []; for ($i = 0; $i < 20000; $i++) { $obj = new Example; $obj->foo = bin2hex(random_bytes(5)); $obj->bar = bin2hex(random_bytes(5)); $obj->baz = bin2hex(random_bytes(5)); $objects[] = $obj; } printMem('before get_object_vars'); // Clone each object, and get the vars on the clone foreach ($objects as $obj) { $c = clone $obj; $vars = get_object_vars($c); // Accessing and modifying the original object is fine. foreach ($vars as $var => $val) { $obj->{$var} = strrev($val); } } printMem('get_object_vars using clone'); // Get the vars on each object directly foreach ($objects as $obj) { $vars = get_object_vars($obj); // The memory is used even if you do not modify the object. } printMem('get_object_vars direct access'); ?> The output of this is: start: 405704 (0.41 MB) before get_object_vars: 6512416 (6.51 MB) get_object_vars using clone: 6033408 (6.03 MB) get_object_vars direct access: 13553408 (13.55 MB) In short, if you are using classes to avoid additional memory usage associated with hashtables (like in associative arrays), be aware that get_object_vars() will create a hashtable for any object passed to it. This appears to be present in all versions of PHP; I've tested it on PHP 5, 7, and 8. Quotes are from Nikic's blog posts on arrays and hashtable memory usage, and Github gist "Why objects (usually) use less memory than arrays in PHP". ---- Server IP: 45.112.84.4 Probable Submitter: 45.112.85.242 (proxied: 72.196.121.168) ---- Manual Page -- https://php.net/manual/en/function.get-object-vars.php Edit -- https://main.php.net/note/edit/125993 Del: integrated -- https://main.php.net/note/delete/125993/integrated Del: useless -- https://main.php.net/note/delete/125993/useless Del: bad code -- https://main.php.net/note/delete/125993/bad+code Del: spam -- https://main.php.net/note/delete/125993/spam Del: non-english -- https://main.php.net/note/delete/125993/non-english Del: in docs -- https://main.php.net/note/delete/125993/in+docs Del: other reasons-- https://main.php.net/note/delete/125993 Reject -- https://main.php.net/note/reject/125993 Search -- https://main.php.net/manage/user-notes.php

« previous php.notes (#216264) next »