Re: Comments about PHPTAL package proposal?
| From: | Greg Beaver | Date: | Sun, 19 Apr 2009 21:15:14 +0000 |
| Subject: | Re: Comments about PHPTAL package proposal? | ||
| References: | 1 2 3 4 5 | Groups: | php.pear.dev |
| Request: | Send a blank email to pear-dev+get-51762@lists.php.net to get a copy of this message | ||
Kornel Lesiński wrote:
> On 19.04.2009, at 17:56, Greg Beaver wrote:
>
>>> This is needed to avoid mix-up of files from PEAR and other
>>> installations of PHPTAL, e.g.:
>>>
>>> include "my/framework/libs/PHPTAL.php";
>>>
>>> won't work properly without enforced path prefix. There's same problem
>>> when running test suite. Does PEAR have solution to this?
>>
>> Yes. Look at how phpDocumentor handles this. You provide a stub file
>> that modifies include_path which other installations then use.
>
> phpDocumentor does:
>> set_include_path(get_include_path() . PATH_SEPARATOR .
>> dirname(dirname(__FILE__)));
>
> which doesn't solve the problem - if PEAR dir is somewhere in the
> path, it will still be used instead of specified directory.
>
> And adding of directories earlier in include_path is unsafe - e.g.
> applications having "config.php" could accidentally include PEAR's
> Config package on case-insensitive filesystem (I have run into this
> problem myself :)
I have not looked at PHPTAL's code directly, but there are definitely
ways to solve this by requiring users outside of PEAR to use a bootstrap
file. One very, very important thing is to make certain all of the
phptal files are in a subdirectory, thus the "config.php" problem simply
won't exist, it will be "PHPTAL/config.php" (for instance).
>> Incidentally, it is never wise to use constructs like:
>>
>> include CONSTNAME . '/path/to/blah.php';
>>
>> because opcode caches will never cache your code at compile-time, as the
>> path cannot be safely resolved until run-time. It makes your code
>> intrinsically slower even with an opcode cache.
>
> I've tested this with APC and it seems to work fine (APC's stats
> report hits for these files). Because include_path can be changed
> anytime, "constant" paths aren't constant either.
>
> One more reason why I like PHPTAL_DIR prefix is that it's an absolute
> directory and PHP doesn't need to stat() directories in include_path
> to load these files.
> As far as I understood, this was recommended by Rasmus in his
> Drupalcon keynote (http://www.archive.org/details/simple_is_hard)
To be honest, I was very skeptical of this claim, having talked in some
detail with Rasmus when we were designing the standards for PEAR2, and
so I watched the presentation, and am afraid to say I disagree with your
interpretation of his recommendations.
Rasmus talks about the high number of stats generated by the sample
twitter-like code. This code uses DB_DataObject, which has (as all PEAR
does) require_once. As Rasmus says "the real path is when we have a
realpath cache miss" which means if your include_path is
".:/usr/local/lib/php", the penalty can be 10-20% over
"/usr/local/lib/php:." as include_path - with no code changes. He also
said that if you are indeed including relative to the current directory,
it is better to use include "./relativepath.php" because PHP treats this
as an absolute path, and performs many fewer stats. This, however, is a
performance recommendation that should only be followed if you always
know what getcwd() will be (which we don't for PEAR or any other library
package).
The other problem was that the _once in require_once causes realpath to
be used, whereas this is not needed for require.
To clarify my point, this is the order of performance without opcode
cache (as tested by a synthetic benchmark using siege, and verified by
Stas Malyshev at Zend labs):
1) include '/full/path/to/file.php';
2) include_once '/full/path/to/file.php';
3) include 'relativepath.php';
4) include_once 'relativepath.php';
5) include CONSTANT . '/relativepath.php';
6) __autoload() with include (no _once)
7) include Blah_Loader::Load('ClassName');
with opcode cache, the speed is similar, but the ratios change.
__autoload performance degraded (for instance), and the include with
full path performance went through the roof.
Also, include and require are basically interchangeable in performance,
with include being ever-so-slightly faster.
Why is include CONSTANT . '/relativepath.php' slower? The difference is
not whether APC caches, but when. With a static include statement, APC
can figure out at compile-time where the file is, and never needs to hit
the executor in some situations. What this means is that APC can turn
the opcodes for the include into NOPs, which is much faster than the
opcodes it takes to replace CONSTANT with its value, concatenate with
'/relativepath.php' and then pass to the include opcode, which calls
compile, which invokes APC (finally).
So, it may not seem like it, but require_once is indeed faster in almost
any situation except for a poor include_path setup.
By the way, these problems literally do not exist in PEAR2. Dependent
file loading is moved to where it belongs - the application level.
Those looking for convenience use __autoload(), and later if the
application becomes performance-intensive, it is possible to move to
faster methods of file loading such as including full path with
__autoload() as a fallback. It also makes it possible to move a package
like PHPTAL to a sub-directory and load it any way the application sees fit.
Thanks,
Greg