Categories


Loading feed
Loading feed
Loading feed

Zend Weekly Summaries Issue #364


TLK: Class resolution [continued]
TLK: Exception policy [continued]
TLK: T_IMPORT vs T_USE [ad infinitum]
TLK: Interbase and PDO_FIREBIRD fixes
REQ: Extension versioning information
REQ: Autoloaded constants and functions
BUG: pack/unpack (again)
REQ: PDO::ATTR_PERSISTENT warning
CVS: ZEND_MM_COMPACT env var
PAT: FastCGI in Russian

21st October - 27th October 2007

TLK: Class resolution [continued]

Stas Malyshev had come up with a new idea. How about some syntax to tell autoload to use a particular namespace? Something like:

namespace Test;
throw new
this::Exception();

- only with something new to replace this - would then mean Test::Exception throughout. Would that help?

Chuck Hagenbuch didn't think it would, since it wouldn't mean you could just import a class once and forget about it. It also didn't solve the problem of having to qualify names from the global namespace if your own namespace included a potential clash. All in all, Chuck concluded, the current behaviour was 'unpredictable'.

Stas wondered why anyone would define a local name when they intended to use something with the same name from the global namespace. He asked Chuck to be very specific about what he wanted, since the use of unqualified names has to work in a consistent manner. It wasn't possible to satisfy all possible scenarios, given that they are contradictory.

Chuck reiterated the main points he made last week, that in his view an unqualified name should always be relative to the namespace and that importing global classes into the namespace should mean you don't need to qualify them. He went on to demonstrate what he meant about unpredictability:

<?php
// file1.php

namespace Test;
import Test::Exception;

throw new
Exception();

?>

<?php
// file2.php

namespace Test;
throw new
Exception();

?>

<?php
// demo.php

function __autoload($class) {
    include
'./test_exception.php'; // defines Test::Exception
}

try {
    include
'file2.php';
} catch (
Exception $e) {
    echo
get_class($e) . "\n";
}

try {
    include
'file1.php';
} catch (
Exception $e) {
    echo
get_class($e) . "\n";
}

?>

demo.php would first throw an Exception, and then a Test::Exception. Reversing the include order, on the other hand, would make the script throw a Test::Exception twice. To Chuck, having the include order capable of changing the way otherwise identical code behaves constituted unpredictability. True, he could resolve the issue by always having import Test::Exception at the head of the file, but if he actually wanted to use the built-in Exception class the only way to enforce it was to always refer to it as ::Exception. He had tried import Exception, which failed due to a naming conflict; import Exception as Error, which threw a fatal error with a bizarre and untrue message about the import name conflicting with a defined class; and import ::Exception as Error, which threw a parse error because it's not possible to import a top-level class name in this way. The only way to write code guaranteed not to break, regardless of the classes future developers might define or import, was to always prefix built-in PHP class names with ::. Chuck believed that, once he'd declared a namespace or import, he should be able to rely on any short name he chose to refer to it; he should have complete control over the meaning of the names within that file. The current implementation had too many 'ifs' in it; 'look inside the namespace, UNLESS there's a built-in class with the same short name and the namespaced version hasn't been autoloaded yet, or there's an explicit import...'. He found it unintuitive that short names within a namespace don't necessarily refer to elements within that namespace; it was also out of step with implementations in other languages.

Stas argued that having unqualified names always relative to the namespace would make the common case harder to implement, that being internal classes that are used directly. Upgrading old code would mean having to go through every namespaced file and adding explicit imports for every built-in class. He also disagreed that there was anything unpredictable about the current behaviour, since it had rules that would allow prediction; and he still didn't understand why anyone would want to define and include a class with the same name as an existing built-in class. Did Chuck want unqualified internal names to work, or not? Stas didn't understand how Chuck managed to get a name conflict message out of import Exception, and asked for more details about this. Importing a top-level class name might be allowed in future, if there was a need for it, but the whole thing about other developers defining or importing classes made no sense to him.

Chuck tried again with a clean PHP snapshot and found that the fatal naming conflicts only occurred when Greg Beaver's initial patch - the one fixing multiple uses of import Test::Exception - was applied. Without that patch, there was merely a weird warning:

The import statement with non-compound name 'Exception' has no effect in...

He felt that either import ::Exception should work, or import Exception shouldn't issue a warning. On the subject of what other developers may or may not do, Chuck suggested that Stas envision large teams working on large projects. He went on to recommend that the Zend team consult the development teams behind a range of large PHP projects regarding the difficulties or otherwise of the upgrade path.

Stas explained that the warning is there because import with a single-term argument is, and will remain, a no-op (read: does nothing). However, he agreed to reconsider the possibility of allowing global imports when prefixed, assuming that anyone else had need of them. The 'large team' argument didn't really hold water though; if there was a chance of a naming conflict arising within a project, why not have the classes from different parts of that project reside in different namespaces?

Greg, writing as PEAR President, said that he felt the ability to simply 'plop a namespace declaration and a few imports' at the head of a file to upgrade existing code was good. He noted that this may mean aliasing top-level classes to another name, but couldn't come up with a specific example. The only use case he could think of where classes might clash would be in an autoloading implementation, since otherwise the executor assumes that the current namespace is intended. He wondered whether it might make sense to have use trigger autoload where the class doesn't exist, and import as a non-autoloading version of the same thing?

Short version: That's one way of putting an end to the T_USE/T_IMPORT debate...

TLK: Exception policy [continued]

Onward with Lukas Smith's quest for a clear policy regarding the usage of exceptions in PECL and the PHP core. Marcus Börger suggested that perhaps there should be written-in-stone rules about this outside the CODING_STANDARDS file, which he interestingly referred to as 'bile'. (Maybe that was a typo?) Lukas, wondering what was so bad about the current CS, asked how Marcus proposed to proceed. Should there be something added to the existing file? Should there be a new CS file for PECL, or should coding standards only apply when a PECL module became a candidate for core inclusion? Marcus replied that all PECL modules should follow the core rules, and if anything the CS file should be made more readily accessible online. (Yep, it must've been a typo.) Lukas wrote that he'd work on it, or else work on improving the current document; he evidently still wasn't sure about the 'bile' part.

Short version: Blame: German keyboards.

TLK: T_IMPORT vs T_USE [ad infinitum]

Stas announced that the Zend team had been unable to find a way to make import work as both a reserved word and a class or function name, and were now looking at use instead. If anyone could foresee any problems with use, 'please speak now (or forever hold your peace :)'. Stas added, a little wearily, that any proposals to replace namespace with package - or with anything else - would be considered off-topic.

Greg asked Stas to hold off; he believed he'd found a simple solution that would solve the problem for class names, methods and functions, but needed to write and test the code before posting it. Marcus muttered that unless he was missing something, this must involve there being no token for the keyword. Stas, rather more optimistically, asked Greg to post his solution as soon as he had it. Greg complied, and added for Marcus' benefit that yes, there is still a token for the keyword.

Unfortunately the patch also covered unrelated bugs and changes, which made reviewing it far more complicated than it needed to be (grr). Greg went into a great deal of detail about his implementation; on the internals side, much fiddling with the lexer to force a T_STRING return wherever possible, but only for import and namespace following T_FUNCTION. He had also used fully_qualified_class_name rather than namespace_name in the parser 'for both import syntaxes' (?); code that will currently throw a parse error (import static::oops as ....) would now give no warning before throwing a fatal when the class was used - something Greg didn't see as problematic.

Giedrius D. spoke for many when he asked if there was any reason not to just use use? He felt that allowing keywords to be other than keywords would bring more confusion than value. Greg pointed out that keywords can already be used as variable names, and nobody gets too confused by that. It wasn't until he was swapping code with Giedrius to prove the point that Greg realized his post had been misleading; his import/namespace only rule applied to class names too. Giedrius, who saw the 'only' part as 'inconsistent', asked again what was wrong with use. Greg explained that to him, use would imply some kind of autoloading. Giedrius retorted that for him, the opposite was true. The only thing they agreed over was that code written for PHP 5.2 should continue to work under PHP 5.3.

There followed yet another exchange between various parties regarding the implicit meaning of use vs that of import. Stefan Walk probably said it best when he wrote that 'the "feel" of the words is probably influenced by your background'.

Short version: I thought we were done with this last week...

TLK: Interbase and PDO_FIREBIRD fixes

New guy on the block Lars Westermann had spent some time exchanging email with Wez Furlong regarding bug fixes for both PHP's Interbase modules. Lars now had a bundle of patches for the PHP_5_3 branch, and noted that any or all of these could easily go into the PHP_5_2 branch too at this stage. He would like someone to review his patches before he committed them.

There followed a brief flooding of the internals list; initially with patched files (Tony Dovgal put an end to that), and then with unified diffs directly in the post, per bug (Derick Rethans and Tony, again, complained). Lars started over for the third time with a cheerful 'Live and learn' and posted more conventional patches, along with detailed explanations of each.

There was still a lot to plough through. Lars had fixes for Interbase bugs #30690 (Resource handle from ibase_execute() becomes invalid after return), #30907 (ibase_query() causing IBserver 7 crash with NULL param as link-id), #39056 (Interbase NUMERIC data type error), #39397 (invalid statement handle in Unknown on line 0) and #39700 (NUMERIC error when result precision are 7,8 or 12-14), with bugs #32143 and #42284 closed as duplicates of existing Interbase reports. For the PDO_FIREBIRD driver, there were fixes for bugs #39822 (new PDO() doesn't work with firebird), #41522 (PDO firebird driver returns NULL if it fails to connect), #35386 (firebird: first row is NULL) and #36128 (Interbase PDO - timestamp columns return NULL), with bug #41522 closed as a duplicate report. As part of the fix for bug #36128, there are now three new Firebird-specific attributes to control date/timestamp formatting: PDO::FB_ATTR_DATE_FORMAT, PDO::FB_ATTR_TIME_FORMAT and PDO::FB_ATTR_TIMESTAMP_FORMAT. These are in line with the existing ibase date and time formatting INI directives.

Lester Caine popped up with news of an unreported bug relating to BLOB ids in the interbase extension, which he claimed had been fixed in the 5.2.4 RC snapshots but not, apparently, in the PHP 5.2.4 distribution. Lars had problems tracking down any changes to the extension in the PHP_5_2 branch, but Lester had his history intact and managed to trace the related bug reports. He added, with the insouciance of a man who knows he will now be heard, that these reports were not bogus.

Short version: That Lars doesn't mess about, does he?

REQ: Extension versioning information

PHP user Gaetano Giunta had come across a bug in ext/oci8. It had been fixed already; that wasn't the problem. The problem was that the PECL extension fix had been in PECL 1.0, and the bundled PHP extension fix in PHP 5.1.6. There was nothing to connect the two, and no way to code around the bug except to test for its presence or to grep for an extension-specific version string.

This wasn't the first time Gaetano had come across such a situation. It was, however, the first time he'd realized that phpversion() can usefully be passed the name of an extension. Sometimes, anyway. Its usefulness depended on whether the extension maintainer had fed a meaningful version string into the zend_module_entry struct, rather than the catch-all NO_VERSION_YET. Gaetano wondered how much it could possibly take to enforce a rule that all extensions must provide a version string... 'starting NOW'.

Short version: Another one for the CODING_STANDARDS bile, perhaps?

REQ: Autoloaded constants and functions

Chuck doesn't give up that easily. He opened a new thread about autoloading namespaced constants and functions, based loosely on Greg's earlier suggestion that import or use statements might trigger __autoload(). While he'd initially seen this as a bad idea, it had the benefit of allowing __autoload() to handle namespaced function libraries and constants - so long as they were imported. What would be needed for this to work would be having __autoload() trigger whenever a fully qualified name is used, regardless of whether that name represents a function, class or constant:

$stuff = My::Namespace::do_stuff();

Here, do_stuff() would be a function in the namespace My::Namespace, rather than a method of the Namespace class in the My namespace. At present, wrote Chuck, __autoload() would be triggered in this situation but fail because My::Namespace isn't a class. The same would be true when accessing namespace constants. Would it be possible, following a failed __autoload() call, to check whether it has become possible to resolve the name to something other than a class?

What Chuck hoped for was the ability to leave the decision about how his library code should be included to the top-level application. Perhaps the application developer might use an autoloader during development but explicit includes in production, for example. He liked that idea, and the advent of namespace support almost made it workable; the only thing preventing it was that namespaced functions and constants couldn't be fully utilized.

Stas squashed the proposal fairly comprehensively. For a start, import is a compile-time name transformation; the class or namespace doesn't actually have to exist. Secondly, an __autoload() that would trigger on any fully qualified name, regardless of the target, wouldn't be __autoload() as we know it. It would have entirely different functionality, and Stas wasn't convinced that many people would need it. The killer was the My::Namespace::do_stuff() example; how, wondered Stas, was the Zend Engine supposed to know whether Chuck intended that to mean a function in a namespace or a method in a namespaced class? As for utilizing functions and constants, there had been no change in policy; you couldn't autoload them before, and you couldn't now; on the other hand, you could utilize them before, and you could now too.

Short version: Don't think about it, it'll make your head spin.

BUG: pack/unpack (again)

Brian Moon put in a last-minute plea for bug #38770 (pack/unpack is broken on 64-bit) to be fixed before the PHP 5.2.5 release. He'd taken the trouble to diagnose the problem, and believed he'd tracked down a commit from last April that caused unpack() to break on his 64-bit Gentoo Linux box. He thought reverting this change should fix the issue; as things stood, his LONG_MAX appeared to be shrinking. Under PHP 5.2.0 on the same machine,

var_dump(unpack("N", pack("N", 2147483648)));

gave him:

array(1) {
    [1]=>
    int(2147483648)
}

but the same line under PHP 5.2.5 RC1 returned:

array(1) {
    [1]=>
    int(-2147483648)
}

Short version: Hopefully this isn't a bug, or Greg may have to shoot someone.

REQ: PDO::ATTR_PERSISTENT warning

Ben Ramsey dropped by with a patch to raise an informative warning on

$pdo->setAttribute(PDO::ATTR_PERSISTENT, true);

Therein lay a tale. His team had been scratching their collective head wondering why the PDO_OCI driver wouldn't create persistent connections. It had taken a while to realize that $pdo->setAttribute() is of necessity called after object instantiation, when the non-persistent connection is already well and truly in place. ATTR_PERSISTENT=>true needs to be passed to the PDO constructor itself, as part of the options array.

By posting his patch, Ben hoped to save others the same confusion.

Andi Gutmans glanced at the patch, and wondered mildly why Ben had chosen to use a switch statement for a single case. Ben cited the likelihood of expansion, which prompted Lukas to head into his Greek chorus role over 'the entire attribute stuff in PDO' and hint - a little over-dramatically - at a need for PDO2.

Short version: PDO attributes need a bit of love.

CVS: ZEND_MM_COMPACT env var

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

  • In ext/mssql, bug #42943 (Move *timeout initialization from RINIT to connect time) was fixed in PHP_5_2, PHP_5_3 and CVS HEAD [Ilia Alshanetsky]
  • Zend Engine bug #35163 (Array elements can lose references) was fixed, along with several variations of the same bug [Dmitry Stogov]
  • In ext/sybase_ct, bug #43074 (attempt to increment refcount outside of the macro) was fixed in the PHP_5_3 branch only [Ilia]
  • In ext/xmlwriter, bug #43099 (XMLWriter::endElement() does not check # of params) was fixed in PHP_5_2, PHP_5_3 and CVS HEAD [Ilia]
  • The ability to control memory consumption between requests using the environmental variable ZEND_MM_COMPACT was added in 5_2, 5_3 and HEAD [Dmitry]

In other CVS news, Dmitry added the -T <count> switch to the CGI SAPI in 5_3 and HEAD. This new switch is intended to measure the execution time of a script over count runs. Jani Taskinen looked through the code, and promptly wrote to make Dmitry aware that he couldn't rely on gettimeofday() being available on the underlying system. Stas briefly wondered which systems, before starting on a plan for a workaround. Dmitry thanked Jani for catching the bad assumption, and promised a fix 'tomorrow'.

It was also Jani who noticed the compact() memory management handler going into CVS a few weeks ago and demanded an explanation. With the aid of setenv() and the new environmental variable, it seems his 'something to use in scripts' has now arrived.

Short version: Good thing someone was awake.

PAT: FastCGI in Russian

A Yusuf Goolamabbas (sp?) tried to interest the Russian-speaking members of the core development team in a published patch to 'greatly improve FastCGI SAPI usage in production'. It had originally been posted on the nginx project mailing list, nginx apparently being a high-performance webserver/reverse proxy.

We're nothing if not well equipped with Russians @php.net. Tony and Stas both went to read the documentation provided, and came back with the response that GPL'd code couldn't be included in PHP. It seems that Tony had already attempted to persuade the author to change his licensing, but without success. Stas wasn't sure why any patching was necessary in the first place; as far as he could tell, the code amounted to a FastCGI controller for PHP. Tony admitted that he hadn't looked too deeply into the code; he hadn't imagined there could be a way to add a process manager without patching the SAPI. Then again, he'd noticed that the code included patches for libevent, and he didn't think it would be a good idea to bundle that even if the author was interested - which seemed not to be the case.

And finally, Dmitry committed a fix to make move_uploaded_file() always set the permissions on the resulting file in line with UMASK. The patch was contributed by one Andrew Sitnikov.

Short version: Nyet.

Comments


Friday, December 21, 2007
THANKS!
8:24AM PST · justinwoods
DITTO..
10:06AM PST · webprofessor [unregistered]