Categories


Loading feed
Loading feed
Loading feed

Zend Weekly Summaries Issue #324


TLK: Runtime JIT proposals
TLK: Backport policy
TLK: Internals newbies
RFC: Debugging overloaded objects
TLK: Globals as CV
TLK: PHP security [continued]
TLK: allow_url_* and fine grained control
NEW: PHP 5.2.1 RC3
BUG: easter_date
TLK: Is this what Stefan Esser was referring to...?
CVS: ext/informix goes West
PAT: Roundness and reference counting

TLK: Runtime JIT proposals

Sara Golemon wrote to internals@ to say that, following some discussion on IRC, she would now be taking over the project to implement runtime JIT in CVS HEAD. To that end, she would like to introduce 'a few proposals of varying complexity and feature-set completeness' for review (the full version is here):

  1. Dump support for compile-time JIT and replace it with a call at runtime using the same semantics.
  2. Leave compile-time JIT alone, and add a second callback for runtime JIT.
  3. Extend JIT signature with a stage parameter to indicate if the JIT trigger is occurring during compile-time or run-time. The callback can decide when/if it performs processing using current return value disarming semantics.
  4. Include fetch type and sub-element during runtime JIT callback, allowing JIT callback to only do work necessary to prepare for the read/write call being performed.

Although there had been an earlier suggestion to turn superglobals into objects with overloaded array access, this would change the behaviour in:

$postdata = $_REQUEST;
foreach(
$postdata as $idx => $val) {
    
$postdata[$idx] = some_filter_func($val);
}

to modify the values in the original $_REQUEST array, which was not acceptable.

Sara's personal preference was for option 4, but any of the others would also be acceptable, and group consensus was important to her. Once this was achieved, she expected to have an implementation for review in a matter of days.

Andi Gutmans, who hadn't been on IRC, didn't immediately make the association with the pre-Christmas JIT discussions or last week's brief exchange, and asked Sara what, precisely, she was trying to accomplish? Sara recapped: the root problem is boosting the accuracy of HTTP input encoding detection in PHP 6, and the general idea was to delay the decoding of $_REQUEST parameters until runtime. To accomplish this, the consensus had been that it would make sense to use the JIT semantics of autoglobals as the mechanism. This meant that JIT would first need to actually be JIT, and the approach to achieving this is the subject of the current discussion.

Rasmus Lerdorf felt that option 1 wouldn't actually break too much, but shared Sara's preference for option 4. It would avoid the overhead of iterating through unused fields, and neatly solved the problem of single-element conversion errors. Given that aspect of the proposal, he felt it wasn't the most complex solution, but one that would simplify things a great deal. He added, as an aside to Andi, that Andrei Zmievski and Pierre-Alain Joye have 'a document on this stuff somewhere' (this was news to list readers), and that the basic problem was that of properly encoding user GPC data. The two big problems with the current compile-time JIT approach were a) getting an encoding error to the user is 'a PITA', and b) encoding becomes more expensive per element.

Pierre intervened to say that there had already been consensus over his initial proposal to add a function and move the JIT to runtime. Sara explained that that consensus had been over compile-time versus runtime JIT; this proposal is about the ways JIT runtime might be implemented. She offered up a view of what it might take to inspect a given request element for encoding hints with an added function:

/* Initially set encoding to ascii just for parsing 'ei' */
http_input_encoding('ascii');

if (!empty(
$_REQUEST['ei'])) {
    
/* Request identified itself */
    
if (!http_input_encoding($_REQUEST['ei'])) {
        
handle_bad_input_encoding();
    }
} else {
/* Fallback on best-guess */
    
http_input_encoding_detect('UTF-8,ISO-8859-1');
}
/* Work with the rest of $_REQUEST using the identified encoding */

Pierre agreed that that was horrible, but explained that a specific userland function for detection wasn't actually what he'd intended. Just two functions were needed, http_input_encoding() to set the encoding and http_input_encoding_error() to handle encoding errors. If the consensus was to go with option 4, he'd prefer 'a more drastic change', perhaps a migration to something like the CGI objects found in perl and python.

Andrei announced that he also liked option 4. There must have been some more IRC discussion and backing at this point, because Sara promptly started work on implementing it. She wrote to the list later to say that it wasn't quite as simple as she'd anticipated. Because autoglobals aren't treated as compiled variables (she'd assumed they were), it was difficult to know whether the whole variable or just a sub-element of it was targeted by the initial fetch. Sara was tempted to 'back up yet another step' and make autoglobals become CV. This would entail extending the zend_compiled_variable struct to include a 'fetch type' flag, which would be populated through fetch_simple_var() during compilation. It would yield the kind of opcode stack she needed to be able to implement option 4 and after that, runtime JIT could be applied to HTTP input encoding detection. As a bonus, having autoglobals as CV ought to speed up the process a little, and she felt it would be worth presenting it as an optimization patch.

Short version: This is the patch that allows the change that will fix the JIT to detect the encoding and shore up the house that Jack built.

TLK: Backport policy

PHP user Reinis Rozitis had been following internals@ with an amazed eye. He bravely posted to the list asking whether the require|include_once() optimization fix by Dmitry Stogov would be backported to the PHP_4_4 branch? In fact his question was a little deeper that this - what he really wanted to know was whether it would be theoretically possible to patch PHP 4.* with certain PHP 5.* changes without breaking the core.

Derick Rethans, as Release Master for the PHP 4.4 series, responded with a brief explanation that no new features would be backported to the branch. Reinis argued politely that this was not so much a feature as a fix in his view, but thanked Derick for his speedy reply. He went on to say that he found some of the topics and discussions on internals@ 'pretty scary' in many ways, and he'd also read claims that PHP 5.2 was faster than PHP 4.* in generic tests but slower in real world applications. This combination was making him very uneasy about upgrading to PHP 5.2.

Brian Moon wrote comfortingly that the same arguments could have been made against upgrading to PHP 4 back in the days of PHP 3. 'It's not a perfect process. It gets ugly sometimes. But, IMO, it works better than one or two people having total control and say in how things are done.'

Short version: PR isn't the core team's strongest point.

TLK: Internals newbies

Arnold Daniels' new extension had been working fine for a while, but had suddenly started getting segfaults 'out of the blue'. He'd managed to locate the function responsible, but couldn't see what was wrong about it since it doesn't do any writes to memory. The error appeared to come from the line ret != NULL...

PHP_FUNCTION(qconf_ini_parse)
{
    zval *in;
    zval *ret;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z", &in, &ret) == FAILURE) {
        RETURN_FALSE;
    }

    if (ret != NULL) {
        printf('1');
    }
    RETURN_NULL();
}

Tony Dovgal suggested Arnold should initialize *ret to NULL, but when Arnold tried that PHPUnit reported a 'FFFFSegmentation fault'. He had no idea what the FFFF part meant. Sebastian Bergmann explained that PHPUnit reports use .FEIS characters, and Tony recommended using a debugger such as gdb to track the real issue. Mike Wallner pointed out that the argument passed to printf() should be in double quotes if Arnold wanted to print a real memory address, but Arnold explained this was only there in the interests of brevity - it didn't exist in his actual code, just in his email. By now he'd become convinced that zend_parse_parameters() puts some strange argument into ret, but planned to try gdb anyway to make sure.

Short version: If zend_parse_parameters() did that, large chunks of PHP would be broken.

RFC: Debugging overloaded objects

Marcus Börger posted a patch introducing a new object handler into the Zend Engine that would help when debugging overloaded objects. It allowed a temporary hash to be returned rather than the object properties, enabling extensions such as SimpleXML to show non-properties in var_dump() and print_r(). Back compatibility was retained by setting the default handler to NULL. Were there any objections to his committing this code into CVS HEAD?

Sara and Mike both liked the idea, although Mike didn't like the name get_debug_info. Marcus presented a short list of alternatives (get_debug_hash, get_dump_vars, get_dump_hash), but those were worse. Mike came up with get_tmp_properties, but nobody else liked that either, so the original name stayed.

Derick thought Marcus had missed an initialization or two (causing warnings in some compilers), but it seems he'd misread the code paths. Marcus altered the code to make it more readable.

PHP user Evert|Pot - only this week he's |FileMobile - asked whether this handler wouldn't provide essentially the same behaviour as __toArray()? Marcus wasn't entirely sure whether Evert meant an array cast (wrong) or a magic method (which doesn't exist), and thought it was questionable whether such a magic method ought to be implemented. If it were, then yes, this would be the same behaviour. He asked cautiously whether anyone felt this new magic method should be implemented but, having no feedback for that, stayed with his original proposal.

Short version: The get_debug_info object handler, plus helper macros Z_OBJDEBUG[_P[P]], are in CVS HEAD. Usage examples in simplexml.c, spl_array.c, var.c.

TLK: Globals as CV

Sara's turn next, and she obliged with 'a shockingly simple patch' that would allow superglobals to be treated as compiled variables. She had a single question, about an opcode check that seemed unnecessary to her in the existing code base.

Dmitry reviewed her patch, and complimented Sara on its clarity. He thought her idea could probably be extended to regular global variables (as in $GLOBALS) too. That said, he wasn't certain of the impact on performance through this particular change; had Sara benchmarked it? As for the opcode check, he suggested she try running

php -r "$x = @$y;"

with and without it. It prevents an error message there.

Sara figured that having the entire GLOBALS expression boil down to a compiled variable would involve rewriting the opcode, but agreed that it shouldn't actually be impossible. As far as benchmarking went, she'd given her patch 'the usual BogoMIPS treatment (Bogus Meaningless Indication of Processor Speed)' and come up with the following figures for one million fetches of $_POST['foo']:

[without patch]
real 0m1.057s
user 0m0.660s
sys 0m0.000s

[with patch]
real 0m0.490s
user 0m0.467s
sys 0m0.000s

Sara liked the 'clever solution' to the problem of localized silence, but pointed out that it would prevent fetches such as $foo = @$bar[$baz]; from becoming compiled variables. Still, that was a small price to pay... would it be sane to commit her patch as-is and look at extending it to encompass $GLOBALS['foo'] -> (global fetch CV)$foo at some later date?

Dmitry asked her to first run Zend/bench.php to check that her patch didn't slow down local fetches, but believed the patch could go into CVS HEAD. He viewed it primarily as a performance patch, and wanted to put all those into PHP_5_3 and HEAD together. Sara obliged, and reported a net gain of only 1% - rather less than she'd imagined. Dmitry responded that she'd made a mistake in the measurement somehow, and the patch was actually OK.

Sara was bugged by the localized silence issue, and - although believing it could be resolved by an optimizer - wrote that she'd try to find a non-ugly solution to allow silenced globals to be CV too. Ilia Alshanetsky advised her that his own optimizer already copes with such things, and he thought it would be best left that way rather than altering the core. Sara wondered how exactly his optimizer manages to turn $_POST['foo'] into a single CV based DIM fetch, but then realized he wasn't precisely doing that... She went back to Dmitry with a proposal, loosely based on Ilia's approach, for fixing the localized silence loophole, writing that 'pushing this all into CV based FETCH_DIM ops' would be very helpful for the runtime JIT project. The idea was that, when the Zend Engine goes to do a DIM fetch based on prior nodes, it would check to see where the container element came from. If it came from a simple FETCH, the Engine would rewrite that to a FETCH_DIM rather than adding a new element to the BP stack. Her benchmark tests showed a miniscule improvement, and Ilia objected that the added parse time would be likely to offset any gains. Not having helped her cause much by posting the wrong patch to the list anyway, Sara contented herself with committing only the original patch into CVS HEAD.

Short version: The basics are coming together.

TLK: PHP security [continued]

Greg Beaver had written at the end of the original thread last week, saying he didn't understand how restricting URLs to truly local stream wrappers could be less secure than disabling URLs outright. Stas Malyshev explained: there is no way to be certain that a user stream is truly local, since the author of the stream wrapper has control over that aspect of it. Greg responded that the solution he envisioned wouldn't allow any access to fsockopen() or the like inside a user stream wrapper. He offered to write an illustrative patch when he had time, but Stas pointed out that evaluating every Engine function that allows remote data access comes dangerously close to the safe_mode problem.

Arnold, still fiddling with his segfaulting extension, wanted to know what would be wrong with simply adding a flag to allow all *:// URLs in functions that open streams? To his way of thinking, streams are an advanced feature in PHP, and those developers using it should be fully capable of ensuring that no URLs are opened. Arnold went on to explain that, as a software developer in a shared hosting company, he believed that it wasn't the job of PHP to ensure that local users can't interfere with other users' files. Other Apache modules have similar issues, and their development teams don't attempt to 'fix' them. With this in mind, his team had produced a kernel patch to allow the current processes to be switched, rather like sudo, and a matching Apache module. Since the privileges only allow the named user or group to access the file, Linux was now responsible for security at that level. Another solution would be to start PHP as CGI as a named user, but that would be less complete.

Alain Williams thought the idea of an allow_all flag was 'brilliant', and commented that the only thing missing was a default configuration option of 'don't allow'. He noted that this isn't the same idea as allow_url_fopen, which leaves the user with no way to specify when remote access is actually needed. Stas was less sure; he asked Arnold what he intended to do with all the functions using streams that don't have fopen arguments? The whole point had been to allow streams to work transparently with all functions. Besides, if the idea was to restrict the local developer (which he was against anyway), then it made no sense to rely on him at the same time. Arnold explained; with fsockopen(), for example, you would always expect to supply a URL, so there should be no restriction there in any case. He simply wanted to see

file_put_contents ($file, FILE_ALLOW_URL);
file_get_contents ($file, FILE_ALLOW_URL | FILE_USE_INCLUDE_PATH);

- the streams_* functions, as he'd said earlier, are an advanced feature, and developers using them could be relied on to look after themselves. In his experience most hacks appear where the user has implemented fopen() or file_put_contents() in an insecure way. This simple change would solve the vast majority of the current streams hacks, rather than make streams 100% safe. All the user would need to do if s/he really intended remote file access would be to add FILE_ALLOW_URL to the function to make it work as currently.

Stas pointed out that Arnold was missing all the other functions that use php_stream_open* - used by 38 files in the PHP source tree alone. All those functions would need to be altered to support the new flag. This was back to the safe_mode scenario, where 90% of the problem areas were plugged quickly but plugging the other 10% never quite ends. Alain and Arnold both felt it better to plug 90% of the holes than none at all, but Stas argued that an effective fix would fix all the issues, not just 90% of them. Arnold retorted that, since the problem only occurs when the function is used insecurely by the developer, it was obvious that those most often mis-implemented would be those most often targeted by hackers. Fixing 90% of the problems here wouldn't open up further ways to hack the site; and, from the perspective of a shared hosting company, he would much rather see one hack per year than one every month.

Matt Wilmas and Alain both wanted to see the kernel patch, and asked whether it was possible for Arnold to 'share it with the world'? Arnold wrote that it was, but he'd like it to be reviewed privately before making it open source; the current version was 'really dirty' and specific to the company's own needs. Anyone wanting to review it should email him off-list for a copy. Alain asked what the patch actually does, and Arnold explained that it allows the user of a running process to be switched. As with sudo, only specific users can switch to other specific users. Apache is run on their set-up under user www-data, which has no privileges other than to switch to any user within the www-data group, and back. CGI instances are run as a new process, and so can't be switched.

Andi responded that his immediate concern would be over resources that have already been opened. Unless they were cleaned up between requests, this could open a hole because it was unlikely that Linux would re-verify permissions on access. That said, he could be wrong, and he would be happy to review the patch.

Short version: New toy.

TLK: allow_url_* and fine grained control

Sara got fed up with the fight over whose shoulders the burden of security should fall on, and posted a patch that would give both site administrator and PHP user more power over the stream types allowed in URL includes.

Her idea was to keep allow_url_fopen and allow_url_include as they are, but enable each to alternatively accept a colon-delimited list of allowed wrapper names, e.g.

allow_url_include=file:compress.bz2:compress.zlib

Using the list format would override the is_url flag in the stream wrapper.

Additionally, Sara had applied the same concept as was recently added to open_basedir, so that the settings can be tightened during runtime or on a per-directory basis, but not loosened. This would allow, for example, a system-wide setting of

allow_url_fopen=1

and a local setting of

ini_set("allow_url_fopen", "file");

to restrict a particular script to local files only.

She added that she'd changed the internal names for the settings in order to force third party extensions to review their code if they relied on those values.

Marcus was very much in favour, calling it 'awesome work', and PHP user Marco agreed that this was a very nice solution to the problem. Ilia was less convinced; he didn't think it was asking a lot of extension authors to set is_url to 1 rather than 0 when working with remote streams, and didn't like leaving security settings in the realm of INI. He saw this as a way of shifting the blame from stream wrapper authors - a limited group - onto a far larger group of PHP users. One of that larger group, Jochem Maas, felt he'd rather have the control - and the blame - than be at the mercy of extensions that may well have is_url set wrongly. However, for it to work well, there would need to be some good documentation and best-practice recommendations available.

Marcus pointed out to Ilia that is_url is quite a misleading name, and leads extension authors to get it wrong now and again; it should probably be renamed. That apart, since the current INI setting only allows a choice of all or nothing, you need to allow all stream wrappers in order to allow any remote stream access. Sara's patch offered much better control, and allowed better security choices to be made by the administrator, regardless of whether extension writers had read the documentation.

David Zülke, who liked the idea, asked whether this meant userspace stream wrappers would also become is_url=1? Sara explained that the patch currently on offer doesn't touch on userspace wrappers; she saw this as a separate issue. Coincidentally, she and Pierre had just been discussing them, and thought it might be a good idea to add a kind of meta-wrapper name that could be used in the whitelist style. For example,

allow_url_fopen=file:http:ftp:user

would allow the file, http and ftp wrappers explicitly, plus any user-defined wrapper. For completeness, there might also be an internal meta-wrapper covering everything not user-defined, although she couldn't quite see the usefulness of that at present.

Richard Quadling came up with a fair point. If a wrapper were denied, i.e. not present on the allow_url_fopen whitelist, but the user meta-wrapper were allowed, wouldn't it be possible for a user-defined wrapper to emulate the missing wrapper and bypass the system-wide restriction?

Short version: Whitelisting may come into its own; meta-wrappers seem a less good idea.

NEW: PHP 5.2.1 RC3

Wearing his Release Master hat, Ilia announced the availability of PHP 5.2.1 RC3 for testing as follows:

The 2nd release candidate for PHP 5.2.1 is now available for download.
The tarballs can be found here:

http://downloads.php.net/ilia/php-5.2.1RC3.tar.bz2
(md5: d3889eda8c3471ce7cf2adb35a4de736)
http://downloads.php.net/ilia/php-5.2.1RC3.tar.gz
(md5: c5b3e5540d1951d4c4b976b8a39c09ab)

and the Win32 binaries will be available in short order.

Since the last release, there are over 20 different bug fixes resolving
some annoying engine issues such as the tempval leak inside foreach().
We do not anticipate any regressions to be introduced by this RC, but
I would still like to ask everyone to take a few minutes and test it
against their code base. If you come across any issues please report
them at http://bugs.php.net/.

Depending on the stability of this release it may either be followed
by a final release or another RC, therefore your feedback is critical
to determining whether or not the code is stable enough to warrant the
5.2.1 final.

Edin Kadribasic wasn't far behind in producing Windows binaries for every occasion. The standard, thread-safe build of PHP 5.2.1 RC3, associated PECL bundle, debug pack and installer are available from http://downloads.php.net/edink/, as are the non-standard NTS (non-thread safe) binaries for FastCGI/CGI/CLI.

Short version: He meant the third.

BUG: easter_date

One Oliver Block wrote to internals@ to report a bug in the easter_date() function that leads to an incorrect return value when the UTC offset of the default timezone is less than the UTC offset of the system timezone. It drops a day...

Short version: Click here.

TLK: Is this what Stefan Esser was referring to...?

Curious PHP user Jochem Maas wanted to know whether this had been what Stefan Esser referred to last week as 'a violation of the PHP license'? He didn't feel strongly about the issue, was grateful for the existence of Chris Shiflett and the PHP Security Consortium, and understood that Stefan's on-list persona can be a little... abrasive, but didn't Stefan have a valid point there?

Stefan confirmed that PhpSecInfo had indeed been his target, but Marcus swiftly intervened to prevent another flame war by saying this was PHP Group business and should be discussed with them, not on the internals list. Olivier Hill grumbled that this was less than transparent and, although he didn't particularly want to debate the point himself, he'd prefer to be informed about it.

Paul Reinheimer noted that a) Chris isn't even the lead for that particular project and b) to the best of his knowledge, nobody has ever mentioned the issue to those actually working on it - including himself - until now. He promised to bring it up in the relevant forum. Rasmus responded to that message, explaining that he'd never considered CSS as part of the PHP source, although he supposed it technically is. The point of the license was to prevent some other team releasing, say, PHP 7, based on the PHP 6 code base. This is in users' interests, not least because the PHP development team wouldn't necessarily know where to begin debugging a heavily modified version (or versions) of PHP. Stefan himself wrote back to Rasmus, pointing out ominously that the PhpSecInfo project not only uses PHP source code and has PHP in its name, but also uses the layout of phpinfo() - up to and including the php.net logo and link.

Short version [thanks Olivier]: Ahh politics...

CVS: ext/informix goes West

Changes in CVS that you should probably be aware of include:

  • In ext/date, bug #39993 (tr_TR.UTF-8 locale has problems with PHP) was fixed in the 5_2 branch (only) [Ilia]
  • Streams bug #40168 (stream_get_wrappers() appends a null-byte) was fixed [Tony]
  • In ext/gd, a fix went into 5_2 and HEAD to correctly save/restore the alpha blending mode in imagefill() and imagefilltoborder(). (A possible end to 4_4 bug #27582 on the horizon?) [Pierre]
  • In ext/curl, it seems last week's new constant CURLOPT_TCP_NODELAY is only available in recent cURL libraries, triggering bug #40169 - now fixed [Tony]
  • In ext/openssl, accessing the public key from an x509 resource is possible once more [Rob Richards]
  • Core bug #39450 (getenv() fills other super-globals) was fixed in PHP_5_2 branch (only) [Ilia]

In other CVS news, Tony moved ext/informix out of the core in PHP_5_2 branch and CVS HEAD. The extension now resides in PECL CVS, but has no maintainer at the time of writing. The actively maintained pecl/pdo_informix extension should be used in new code.

Meanwhile in the blue-ridged mountains of CVS HEAD, Andrei noticed that the PHP API version was still ancient (PHP 5.0!) and promptly updated it to reflect reality.

Marcus kept himself busy adding 'more Unicode stuff' to the PHP API. We now have php_stream_u_opendir(), php_u_stat() and (later in the week) zspprintf() and vzspprintf(). He also went to work seriously on ext/spl, getting to hear from Andrei about all the macros he never knew existed immediately after his first commit. By the end of the week, though, Marcus commented that everything in the extension is now Unicode safe; there are just a few additions and clarifications still to be made there.

Short version: There can't be many core extensions left to Unicodify. Grab one quick!

PAT: Roundness and reference counting

At the beginning of the week, Tony applied a fix for bug #40129 (iconv extension doesn't compile with CodeWarrior on Netware) that was supplied by the bug reporter, gk at gknw dot de.

Ilia applied two patches to the PHP_5_2 branch only - one from Matt Wilmas, fixing the syntax highlighting in hexadecimal numbers, and one by Hannes Magnusson ('mostly') that adds a read-timeout-context option, timeout, to HTTP streams.

Meanwhile Christian Schneider had tracked down the failure of test script bug24142.phpt on SUSE 10.0 with gcc 4.02, and found that the roundness check in ext/standard/config.m4 didn't work for him. He'd produced some code to detect the correct PHP_ROUND_FUZZ there, but the same problem doesn't occur under SUSE 10.1 and gcc 4.1.0, and he wasn't certain that his changes wouldn't break the configuration elsewhere. Gentoo developer Luca Longinotti turned up with the correct fix, explaining that it had already been applied to the PHP 5 branch some time ago, but never backported to PHP_4_4. Christian mailed Derick to ask whether the patch might make it into PHP 4.4.5, but had had no response at the time of writing.

One Lars Schultz posted a feature request; he wanted to be able to pick up the number of references currently pointing to an object. He hoped to cache objects in a singleton-like way, relying on the reference count for safety, something like:

/**
* Removes any object from the cache-list which is not referenced anymore.
* (safe for the list and the local-reference to it)
*/
public static function collect() {
    foreach (
self::$instances as $id => $instance) {
        if (
reference_count($instance) < 3)
            unset(
self::$instances[$id]);
        }
    }
}

Andreas Korthaus wrote that he'd written a patch implementing this some time ago, but wasn't sure if it was reasonable - or whether something like this was actually needed in the PHP core. Whatever. He posted his patch against current PHP_5_2 in the hope of getting it reviewed.

Stas explained to Lars that the Zend Engine can't guarantee the reference count, because anything from passing parameters to accessing variables can alter it. The only thing that is guaranteed is that, once there are no links to a variable, it will be destroyed - but even then, it may not happen immediately. Actually figuring out and getting the appropriate information to userspace 'could prove non-trivial', depending on the structure of the application. Stas went on to review Andreas' patch, and explained that he'd actually exposed the zval reference count; there can be any number of zvals referencing the same object, and the object storage keeps its own count. Given that each zval can hold its own count, and there's no way to know which variables reference the chosen object, the only way to calculate the number of references would be from the outside - meaning you'd need to know your application very well indeed.

Paweł Stradomski suggested keeping a reference count in userspace, by keeping the 'real' objects in a private array and returning a simple object that forwards the object methods and properties using __get(), __set() and __call(). The constructor would increase the reference count by one, and the destructor, decrease it.

Short version: Things are rarely as simple as they seem.

Comments