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):
- Dump support for compile-time JIT and replace it with a call at runtime using the same semantics.
- Leave compile-time JIT alone, and add a second callback for runtime JIT.
- Extend JIT signature with a
stageparameter 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. - 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;
|
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' */
|
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)
|
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);
|
- 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-8locale 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()andimagefilltoborder(). (A possible end to 4_4 bug #27582 on the horizon?) [Pierre] - In ext/curl, it seems last week's new constant
CURLOPT_TCP_NODELAYis 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:
/**
|
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