Rethink CS for require_once?
| From: | Greg Beaver | Date: | Wed, 01 Dec 2004 03:04:27 +0000 |
| Subject: | Rethink CS for require_once? | ||
| Groups: | php.pear.dev | ||
| Request: | Send a blank email to pear-dev+get-34678@lists.php.net to get a copy of this message | ||
Hi,
I would like to suggest a simple and compelling change into the CS for require_once in PEAR packages. Currently, all internal inclusion of PEAR files must be done like
require_once 'Relative/Package/FilePath.php';
I'd like to revisit this CS and split it into two kinds of includes:
1) inclusion of internal package files
2) inclusion of external package files
definitions:
1) internal package files
drivers
internal extensions (PEAR_Command commands, PEAR_PackageFile_v1
any internal file that must not be changed (can be considered final)
2) external package files
*any* file that is not in the package.xml
any internal file that can be user-customized
So, the new standard would be:
for (1) use dirname(__FILE__) for absolute inclusion
require_once dirname(__FILE__) . '/Foo/Driver.php';
This means that any supporting files must be included by parents. This hypothetical include from Foo/Driver.php would not be allowed:
require_once dirname(dirname(__FILE__)) . '/Foo.php';
and would instead have to be included in the relative manner
require_once 'Foo.php';
To be clear: the ONLY new syntax allowed would be including deeper files
from Foo.php
require_once dirname(__FILE__) . '/Foo/Driver.php';
require_once dirname(__FILE__) . '/Foo_Unserializer.php';
from Foo/Driver.php
require_once dirname(__FILE__) . '/Driver/Subhelper.php';
require_once 'Foo_Unserializer.php';
no funny business like
require_once dirname(__FILE__) . '../FooUnserializer.php';
would be allowed either.
for (2) use the old way require_once 'Relative/Path/To/File.php';
Why?
1) errors caused by include_path go bye-bye
phpDocumentor has run into trouble when the include_path has a version installed by PEAR after a version that is downloaded from sourceforge, mainly because of the unnecessary use of relative includes.
In addition it enforces better design. If you are extending DB_mysql and putting it in /path/to/home/DB/mysql.php, where PEAR is in /usr/local/pear/DB/mysql.php, and you use include_path ".:/path/to/home/:/usr/local/pear" it can lead to sudden breakage caused by upgrading the server version, and very difficult bugs to trace. In addition, how many times have people suddenly gotten messages like:
"undefined function fetchRow()"
when they define a file named "DB.php" in the . directory?
Anyone who wants to override Foo::factory() can either extend Foo, or Foo could follow the path offered by Log, and attempt to include user-designed drivers from a specific path first, and then from local directories.
2) it opens up unique possibilities with Davey's new package and other yet-uncoded solutions.
require_once dirname(__FILE__) . '/DB/mysql.php';
will include 'phar://DB-1.6.8.phar/DB/mysql.php' if DB.php is __FILE__ and it was included with require_once 'phar://DB-1.6.8.phar/DB.php';
3) performance is notably faster with absolute paths at script startup, although this is a distant third. I'm most concerned with keeping the include_path cleaner for internal files. This also makes include_path less of an issue for packages extracted into a non-PEAR environment which is *always* a good thing.
For an example of clean require_once, check out Harry Fueck's Calendar code, which raised some flack when he proposed it. Also, check out the internal driver inclusion of PEAR's own PEAR_Command (uses dirname(__FILE__) unless the user specifies a directory where commands reside).
Greg