By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,039 Members | 1,035 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,039 IT Pros & Developers. It's quick & easy.

include_once/__autoload/namespace emulation ...

P: n/a
The primary problem I've had with php is the lack of namespaces, which
makes OOP very difficult to organize, since you end up with large number
of classes cluttering up the same namespace - which leads to a secondary
problem involving php's __autoload feature. Since you cannot specify a
namespace when calling a class that may not have been included, you are
forced to store all of your classes in the same folder in your file
system. This can get quite unwieldy. I've also read that __autoload has
a performance hit over using a standard include (I'm not sure if this is
still true). Finally, I've read that require_once can be very buggy in
the php documentation comments. (Is that true?)

After thinking about the namespace problem, I've concluded that php's
conditional include nature keeps the runtime environment pretty clean
(if I have two classes with the same name, I don't usually have to worry
about it, since I will usually only include one at a time) and its
runtime footprint small. While it's not perfect, it does provide enough
of something like runtime namespace protection, at least enough to keep
me from creating a bulky framework to emulate more robust namespaces.

This left me with the problem of organizing all of my class files on the
file system. I do not want to keep 100s of classes in the same one
folder - especially since there are many classes in there that will
probably not be used, but I'd like to keep around for just in cases.
Since __autoload seems to have performance issues, I decided not to use
that either. (Is this still an issue?)

Since I've decided that for my needs php's include functions are a good
enough substitute for real namespace imports I just needed a way to load
class files that are organized in a namespaces like folder structure. I
would have just used require_once, but it has those bugs I mentioned. So
I came up with a single function that I named "using" (borrowed from
..NET and Prado - which actually has a pretty spiffy solution to the
namespace problem that uses __autoload).

Here is the function (it is horribly unoptimized and probably buggy):

$namespaces = array();
$classPath = 'C:/Inetpub/wwwroot/_domains/adcecart/_includes/';
/**
* Includes class files, which are stored in Namespace like folders
* @param string colon delimited namespace string.
*/
function using($namespace) {
global $namespaces, $classPath;

// quick return if repeat import
if(isset($namespaces[$namespace])) return;

// convert $namespace to path
$path = $classPath . str_replace(':','/',$namespace);

if (is_dir($path)) {
// add namespace to hash (to avoid double import)
$namespaces[$namespace] = $namespace;

// add all files in the directory
$dir = dir($path);
while (false !== ($entry = $dir->read()) ) {
if (preg_match('/.php$/i', $entry)) {
$newNamespace = str_replace('/',
':', substr($namespace.'/'.$entry, 0, -4));

if (!isset($namespaces[$newNamespace])) {
$namespaces[$newNamespace] = $newNamespace;
require_once($path.'/'.$entry);
}
}
}
$dir->close();

} else if (is_file($path.'.php')) {
$namespaces[$namespace]=$namespace;
require_once($path.'.php');
} else
exit('Error importing namespace.');
}

// used like this
using('unFocus:Feature:ClassName');
This actually does one more thing than a simple enhanced require_once -
it can import all of the php files in a specific folder (or namespace).
I don't use this feature, and will probably remove it unless I find some
need for it.

This function works differently (and I use it differently) than a
regular namespace implementation would. In other languages, namespace
imports (or using) are tied to the specific class file scope, and only
applied to class within that class. As far as I can tell, php has no
similar scoping rules (since it is an inline interpreter, unless
something has changed that I am unaware of), so this will just include a
class file (and anything else that might be in that file actually - like
spare functions or variables), and dump all that into the global scope
(except variables).

This can also be used with performance in mind - let's say you want to
use a class from another class, and you will only need it if conditions
are met. You don't have to import the class if you don't need it, saving
memory, parsing, and cpu time. To me this is a benefit, since php is
really an inline interpretor at the end of the day (unless you use an
opcode cache I guess).

At this point really just rambling, so I'll just finish up with a summary.

The goal was to be able to organize and group my class files in some
kind of reasonable way - namespaces provided that way, but are
unavailable in php. Understanding the nature of php's inline
interpretation, conditional includes and __autoload's inability to cope
with a namespace like directory structure and its possible performance
consideration convinced me that a simple require_once function used with
classes named carefully would actually be adequate to make sure I was
only importing classes that I needed and that they would not clash with
one another or with built in php classes (I've never run into that
problem yet). After trying out a bunch of different namespace solutions,
I wrote a simple function (which can be a lot simpler) that will include
the necessary class files only once, when they are needed, and not
before, from within their namespace like directory structure.

Now the question! :-) Basically - What do you think of my reasoning and
rational?

Also, if I'm wrong about any of the details of how PHP works, I'd
appreciate some clarification on anything I got wrong.

Thanks,

Kevin N.
Nov 28 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a
Namespaces and PHP are certainly an issue, some of the things you wrote
I have never heard of before, like require_once being bugged.

Pear is a good example of how namespaces should be done but I would
suggest an even simpler solution.

Say you have a folder structure like:
classes

XML
Parser.inc.php
Transformer.inc.php
DB
Mysql.inc.php
FILE_SYSTEM
File.inc.php


They you should have an auto load function like:

function __autoload( $class )
{
$load = strtolower( str_replace( "_", "/classes/", $class ) ) .
".inc.php";
if( file_exists( $load ) )
{
include_once( $load );
}
else
{
die( "Can't find a file for class: $class \n" );
}
}

Now you can have

$obj = new XML_Parser();

(example adapter from http://www.wiki.cc/php/Overload_autoload).

This makes things allot easier. The drawback is it is not php4
compatible.

Nov 29 '05 #2

P: n/a
Sean wrote:
Namespaces and PHP are certainly an issue, some of the things you wrote
I have never heard of before, like require_once being bugged.

Pear is a good example of how namespaces should be done but I would
suggest an even simpler solution.

Say you have a folder structure like:
classes

XML
Parser.inc.php
Transformer.inc.php DB
Mysql.inc.php FILE_SYSTEM
File.inc.php


They you should have an auto load function like:

function __autoload( $class )
{
$load = strtolower( str_replace( "_", "/classes/", $class ) ) .
".inc.php";
if( file_exists( $load ) )
{
include_once( $load );
}
else
{
die( "Can't find a file for class: $class \n" );
}
}

Now you can have

$obj = new XML_Parser();

(example adapter from http://www.wiki.cc/php/Overload_autoload).

This makes things allot easier. The drawback is it is not php4
compatible.


I thought of that, but doesn't it try to load "XML_Parser" from within
the class file, instead of just "Parser"? In some cases that would lead
to to huge class names (and a lot of typing).

Also, I've read that there is a performance problem with __autoload -
has that been taken care of? (I read that php 5.1 improved some of the
performance issues with magic functions.)

I really wish the php guys would just implement at least class level
namespaces (they already have a patch).

Kevin N.
Nov 29 '05 #3

P: n/a
I think I messed up my example $obj = new XML_Parser(); should load
/classes/xml/parser.inc.php which simplifies things (if I did mess up
the website I quoted has it done right). And it also means allot less
typing. No more 10 lines of includes at the beginning of your scripts.
Just an autoload.

Again I have never heard of performance issues with autoload. In work I
do in php I don't even use that function though.

There are allot of improvements to php that need to be made. Class
level namespaces probably being one of them, removal of magic quotes
and register globals and so on. Where php is at the moment they can't
really change too much without the risk of breaking backwards
compatibility.

Nov 29 '05 #4

P: n/a
On Tue, 29 Nov 2005 15:33:06 GMT, Kevin Newman <Ca******@unFocus.com>
wrote:
I thought of that, but doesn't it try to load "XML_Parser" from within
the class file, instead of just "Parser"? In some cases that would lead
to to huge class names (and a lot of typing).
Huge class names really isn't an issue. You just don't 'new' objects
very often. Unlike in C# or Java, you don't have to declare the types
of variables so you just don't end up using full class names very
often at all.

I have a PHP5 project with 446 classes, arranged in the hierarchy
(XML_Parser is in XML/Parser.php) and I use __autoload.
Also, I've read that there is a performance problem with __autoload -
has that been taken care of?
I never experienced any performance issues with __autoload. In fact,
a quick googling for "__autoload performance" leads to a number of
posts/articles saying how it has improved performance of applications.

This makes sense, as __autoload only loads classes on demand. With
require/include you're loading classes whether or not you are actually
using them.
I really wish the php guys would just implement at least class level
namespaces (they already have a patch).


I honestly think you're over-thinking this. In reality, namespaces
are simply not the issue in PHP as they are for other languages. I
just use nice long class names.

Nov 29 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.