Re: Making PEAR2 Portable
| From: | Gregory Beaver | 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