Re: Making PEAR2 Portable

From: Date: Sun, 09 Sep 2007 17:39:09 +0000
Subject: Re: Making PEAR2 Portable
References: 1  Groups: php.pear.dev 
Request: Send a blank email to pear-dev+get-47953@lists.php.net to get a copy of this message
David C. Morse wrote: > > I've been thinking about this thread about how PEAR2 might handle > dependences so as to allow PEAR2 packages to be embedded within > self-contained unzip and go applications. I think this goal is worth > considering. > > Comments and proposals: > > 1) PEAR 2 packages can only work as part of a standard PEAR2 directory > tree. All PEAR 2 packages will depend on other PEAR packages. If nothing > else, they will all depend on the PEAR2_Exception class. The references > among files in a PEAR installation all rely on a standard directory > structure. The only way to embed a PEAR package within another > application that we should try to enable should thus be inclusion of a > stripped down > version of the standard PEAR2 directory tree as a subdirectory of the > application. The minimally functional directory tree would include the > Exception class and PEAR2::Autoload function, and I'm not sure what else. Hi, Thanks for the extensive thinking that went into your post, it's always good to see another viewpoint. Actually, the minimal requirement is PEAR2_Exception. Files can be manually loaded using include with absolute paths. Truly include_path-independent code does not need autoload, which is proven to be quite inefficient even with a code optimizer. > 2) For this kind of embedding to work, references among PEAR2 classes > and files, within the PEAR2 directory tree, could not rely at all on > include_path. The directory tree would have to be entirely portable - if > you move the whole tree, everying should still work correctly. Inclusion > of PEAR2 files into user code outside this tree might or might not depend > on the include_path containing the root PEAR2 directory - that would be > up to the user. This is done in the current PEAR2 proposal by having no usages of "include" statements at all, and by using relative references to data files using __FILE__ and relying upon the known directory structure of PEAR2 packages. > 3) If the PEAR2_Autoload function becomes the standard way to load PEAR2 > classes, perhaps this function should thus define paths to class files > using something like: > > $PEAR2_root = __FILE__ . '/..'; > $full_path = $PEAR2_root . str_replace('_', '/', $class) . > '.php' > > The use of a relative reference to __FILE__ guarantees that the Autoloader > constructs absolute paths correctly, without any reliance on include_path. > It looks to me like the current version of PEAR2::Autoload() in svn assumes > that the include_path contains the PEAR2 root. PEAR2_Autoload is intended to be a convenience function for development and low-traffic sites where performance is not an issue. As such, there is in fact intentionally no standard way to load files in PEAR2, but two possible ways of doing it: 1) include PEAR2_Autoload.php and then simply use PEAR2 classes without thinking about where they came from 2) write a customized loader script that includes all needed files manually. The second way is a lot more work, but will be worth it to performance-hungry site admins. Relying upon include_path provides flexibility that allows users to define where to look for classes, possibly in cascading PEAR2 installations, so that classes are first looked for in a local PEAR2 install, and then in a system PEAR2 install. Using __FILE__ eliminates this as a possibility. The current system of setting up include_path if it doesn't already contain the directory relative to PEAR2/Autoload.php is again a convenience. The current PEAR2_Autoload makes no assumptions about include_path, but in fact sets it up if it isn't there, perhaps you're looking at an outdated version? > 4) To help load data, or other PEAR2 files that aren't class definition > files, PEAR2 should also provide a standard way to obtain the root > directory of the current PEAR installation. This could be implemented > as either a data member or the return value of a method of a PEAR2 class, > so it can be found by the PEAR2::Autoload function. This path could > also be determined using a relative reference to __FILE__ in code with > a known location in the PEAR2 directory tree. There is a standard way - each role="php" file is always installed into the same relative location within php_dir. All you need to do is strip the location (i.e. PEAR2/Class/Name.php only needs to strip PEAR2/Class/Name.php from __FILE__ to retrieve php_dir, and src/PEAR2/Class/Name.php from __FILE__ to find the root of installation, and add data/pear2.php.net/PEAR2_Package/ to find data files). No need for extra dependencies on slower functions provided by a base PEAR2 class. > 5) Perhaps PEAR2 should simply provide a somewhat simpler PEAR::AutoLoad > function than the one now in svn, and then give users clear instructions > of several ways to make sure it gets used as the (or a) autoload > function. Instructions could be given in the manul of several ways to > accomplish this: > > i) For beginners: Instruct the them to add the following line to > user code: > > require 'FullPathto/PEAR2/__autload.php'; How is this any more intuitive than include 'FullPathto/PEAR2/Autoload.php';? You're asking users to now be able to locate 2 different files. It's also important to note that the autoload implementation itself is 3 lines long. Anyone who needs further customization can write their own autoload quite easily and ditch PEAR2_Autoload altogether. > The PEAR2/__autoload.php file file would then contain a one-line > implementation of the magic __autoload() function that calls the > custom PEAR2::autoload() function internally: > > <?php > function __autoload($class) { return PEAR2_Autoload($class); } > ?> > > Perhaps I'm missing something, but don't see the point of having > the PEAR2_Autoload() function try to define the magic __autoload() > function internally, as done in the current svn implementation. > If the PEAR2_Autoload function will normally be called only from > within an __autoload() function, then an __autoload() function must > necessarily be defined before PEAR2_Autoload() is called. The point is to provide something with which absolute beginners can add 1 line of code to their apps and simply start using PEAR2 packages. > ii) For user that prefer to define a custom __autoload function: > Give examples of how to call the PEAR2::autoload() function from > within a more complicated user defined __autoload() function. You mean like: if (PEAR2_Autoload($class)) return true;? Anyone who is in the process of customizing an autoload will have the technical know-how to do this, or to simply add these lines of code to their own __autoload: if (substr($class, 0, 6) === 'PEAR2_') { $fp = @fopen(str_replace('_', '/', $class) . '.php', 'r', true); if ($fp) { fclose($fp); require str_replace('_', '/', $class) . '.php'; return true; } } > iii) For a user that prefers spl_autoload_register : Explain how to > register the PEAR2::Autoload function. It would be up to the user > to use the spl autoload stack in a way that avoids conflicts > between autoloader implementations used by different libraries > or packages. This is explained in http://php.net/spl_autoload_register I'm not sure it is wise for us to duplicate documentation, but a link to the PHP documentation would not hurt. > This way, PEAR2 supports __autoload() and spl_autoload_register equally > well. If this solution were accepted, you would also remove the code in > the current PEAR2_Autoload that tries to reset the include_path - the > whole goal would be to make the include_path irrelevant for the functioning > of the autoloader. > > Comments? Anything obviously wrong? Just that I think the point of PEAR2_Autoload() may not have been obvious enough - to provide a convenient one-liner for accessing all PEAR2 packages. Your comments did prompt some changes to the autoload implementation: 1) after loading the file that should contain the class, an extra check is added to ensure that the class indeed exists, and an exception is thrown if this is not the case to assist in debugging. 2) if SPL is loaded, spl_autoload_functions is checked for the presence of PEAR2_Autoload, and is registered. if __autoload exists, it is also registered if no spl_autoload stack was active. 3) all global variables used are prepended with a bunch of ____ to make sure they don't conflict with any that may exist in the user code, and are unset at the end of the file. http://svn.pear.php.net/wsvn/PEARSVN/Pyrus/trunk/src/Autoload.php?op=file Thanks, Greg

« previous php.pear.dev (#47953) next »