Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:40676 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 60243 invoked from network); 25 Sep 2008 05:26:23 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 25 Sep 2008 05:26:23 -0000 Authentication-Results: pb1.pair.com header.from=mark@hell.ne.jp; sender-id=fail Authentication-Results: pb1.pair.com smtp.mail=mark@hell.ne.jp; spf=fail; sender-id=fail Received-SPF: fail (pb1.pair.com: domain hell.ne.jp does not designate 91.121.140.141 as permitted sender) X-PHP-List-Original-Sender: mark@hell.ne.jp X-Host-Fingerprint: 91.121.140.141 shigoto.ookoo.org Linux 2.6 Received: from [91.121.140.141] ([91.121.140.141:39567] helo=Shigoto.ookoo.org) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 0E/C2-39651-CF02BD84 for ; Thu, 25 Sep 2008 01:26:23 -0400 Received: (pmaild 232454 invoked for user karpeles@ookoo.org); Thu, 25 Sep 2008 07:26:17 +0200 Received: from [192.168.0.25] (30.3.207-77.rev.gaoland.net [77.207.3.30]) by Shigoto.ookoo.org (phpinetd by MagicalTux ) with SMTP version 1.0; Thu, 25 Sep 2008 07:26:17 +0200 To: 'PHP Internals' Content-Type: text/plain Date: Thu, 25 Sep 2008 07:26:17 +0200 Message-ID: <1222320377.1712.169.camel@localhost> Mime-Version: 1.0 X-Mailer: Evolution 2.22.3.1 Content-Transfer-Encoding: 7bit Subject: Classes userland lookup (with namespaces) From: mark@hell.ne.jp (Mark) Hi, I've been using namespaces for a few months now, and I feel a need for a specific solution. I've been thinking a lot about this, and I will explain everything here. Basically the goal is to be able to overload namespace resolution (ie. overloading new and static calls). Basically (case 1), the user would create a function __resolveclass($classname, $cur_namespace, $used_namespaces) which would return a string. When new or a static call happens, this function is called and the final call happens to whatever was returned. The second argument would contain the current namespace (where the call happened) and the last one would contain list of "used" namespaces. It is possible to implement a cache (eg. if the same class is called we just get the last value we got from __resolveclass()) but in this case a function like clear_cache_resolver_cache() would be needed. Another implementation (case 2) of this would be to create virtual namespaces. In this case a function create_virtual_namespace($namespace, $callback) would be created, and any new/static call on a class within the given namespace would call $callback. The basic idea behind this is to allow this kind of calls : (from global scope) use something; $database = new virtual::SQL(); virtual::SQL::DoSomethingInteresting(); Both calls would call either : Case 1: __resolveclass('virtual::SQL', '', array('', 'something')); Case 2: my_callback('virtual', 'SQL'); (first parameter would be the virtual namespace, the second one would be the class name). While working with namespaces, I basically had namespaces extending other namespaces (a collection of classes which extends another collection of class, and all implement the same interface). However in some cases one of the class has no need to be extended. In this case it's just not created. In order to implement this, I wrote my own "class resolver function" which will lookup the class' file in current namespace, and in each "parent namespace" until it finds it, then returns the class name so I can do a new $class(). Another case where this is necessary is on a totally unrelated project: we are working on a quite big framework, and the same codebase is being used for more than 100 websites. The codebase itself is really huge, and we replace parts as time passes by, and try to write new "modular" code. Our need was to overload creation of some classes, but only for some sites which have really specific needs. Since some of those classes are static, a class factory isn't good enough, and (even if it's our goal) we can't rewrite the whole code to make it new and better. Being able to overload the new operator would allow us to make a better class lookup to fit our needs, and probably other people's needs too, which can't just be implemented in PHP (the class lookup). I'm perfectly aware of the risks of obscure code spawning from the hands of various people if this gets implemented, it was the same when classes were implemented, when __autoload() was used (I saw people do what I wrote here using __autoload and eval() to create an empty class extending the target class on the fly) and there will be with namespaces, probably with unicode support too. You can't just create something and expect everyone will use it right, but at least it's possible to document it and help people avoiding non-maintainable code. Anyway right now this is more on the discussion step, I think as PHP 5.3.0 gets released with namespaces, the need for this kind of solution will arise (I'm probably the only one here who really used namespaces in a whole PHP project, and saw how useful/harmful they are). If anyone here have a better solution, I'm ready to implement and test it too. Anyway a solution is needed before people do things like : // Eeeeek-autoload, using eval() to create empty classes function __autoload($class) { $aClass = explode('::', $class); if ($aClass[0] == 'virtual') { $real_class = 'None'; switch($aClass[1]) { case 'SQL': $real_class = 'MySQL'; break; } normal_autoload($real_class); eval('class '.$class.' extends '.$real_class.' { }'); return; } normal_autoload($class); } (and it could be even worse, if for example overload is not only for one namespace but for random class names). By the way dynamic class lookup is something only runtime languages like PHP can do, so don't try to compare this to anything found in C++/Java/etc (or any other compiled language). Best regards, Mark Karpeles