I find myself writing frameworks all the time, each with different features, different ways of going about things and different focuses.
Off Topic:
Strangely enough, I rarely do projects beyond the framework stage. I suppose its the theory and potential I enjoy rather than extending it to something useful. Anyone else in the same boat?
One thing that I change between projects is the way one file imports another, inside an application. Usually the method Iād use is:
The main application initial file loads all the function files
It then loads the main system class files
Autoloading is used to load models etc
However, one thing Iāve been using in my latest framework is include_onceāing all files required in every file. For example, if the action/view of a model needs to load model and a function file for creating a short summary from a larger text, it would start with:
I find that, this way, only functions that are needed are loaded, and a plugin could almost act stand-alone, as long as it was included from a file giving it the required start-up variables.
So, I was wondering - what is your preferred including/requiring method in your applications? What are the benefits over other methods?
I favour autoloading pretty much everything since it makes adding and removing class files fairly transparent. Secondly there is an implicit cost in using include_once or require_once which autoload does not have. Thirdly, opcode caches like APC have āissuesā with the *_once functions.
The most performant approach is using plain include/require but that has itās obvious drawbacks too.
For me, itās [fphp]spl_autoload[/fphp] all the way. For one, itās stackable, so I can have individual components with their own Autoload implementation and as long as they play nice (failing early with a request for non-component object) I can swip-swap 'em about as much as I like.
In addition to this, I find itās easier to manage the application or autoloading of objects when I have a central place to control it.
For instance, given this, in my bootstrapā¦
class Application_Autoload
{
static public function Register(){
return spl_autoload_register(
array(
'Application_Autoload',
'Load'
)
);
}
static public function Load($objectName){
#validate, require_once
}
}
Application_Autoload::Register();
I can quite easily add behaviour to how the objects are supplied in the Application_Autoload::Load method, maybe store a map of where the required files are stored or filter out certain requests.
I find myself just doing a require_once for all classes I need. I see no need to do an include if you NEED that particular function/method. If you go with āwell at least some of the page can loadā then whatās the point in showing a broken page for?
I honestly donāt see the need for an autoloader method. Whatās the difference between using require_once and autoloading? When you initiate an object, itās gonna be required/included for you anyway.
class foo {
public function __autoload($class_name) {
require_once $class_name . '.php';
}
//Or
public function __autoload(array $classNames) {
foreach($classNames as $class)
require_once $class . '.php';
}
}
//When you can just do this:
require_once 'class.b.php';
class c extends b {
}
//Or
require_once 'functions.php';
class c {
}
Both locations (either at the top or in _autoload) provide a nice location to store all the external files that are needed. The only reason to actually use autoloader if it had some type of performance increase. And in that, case, how much more of a boost would it really be? I would imagine that it would be marginal.
Something did catch my attention though, and thatās Anthonyās way with spl_autoload. It seems to provide that little extra reason to go with it then just plain autoload.
I use autoloading, I donāt really like having to use include or require anywhere in my code unless I must. I mostly use indexing cause I use strange naming conventions and structuring.
<?php namespace Markdown;
/**
* Attemps to assign a global "__autoload" function to spl_autoload stack. Using
* spl_autoload_register overrides any global "__autoload" function.
*
* Builds an index from the respected "__load.php" files in each component.
*/
function __load ()
{
// No need to re-run the function if its already in.
if ( in_array( 'Markdown\\\\{closure}', (array)spl_autoload_functions() ) )
return;
if ( function_exists( '\\\\__autoload' ) )
spl_autoload_register( '\\\\__autoload' );
$index = array(
'config' => '/config.php',
'parser' => '/parser.php'
// class => file ...etc
);
// Not required in this project
//foreach ( glob( __DIR__ . '/[a-z]*/__load.php' ) as $load )
//$index = array_merge( $index, ( include $load ) );
spl_autoload_register( function ( $class ) use ( $index ) {
if ( strpos( $class, 'Markdown\\\\' ) === 0 ) {
$class = strtolower( str_replace( 'Markdown\\\\', '', $class ) );
if ( isset( $index[ $class ] ) )
include __DIR__ . $index[ $class ];
}
} );
}
__load();
I have a handler class which has methods to load models, controllers and views. This provides my core application, then I can extend each element on an instance by instance basis.
function loadModel($classname)
{
$this->classname = $classname;
$this->loadclassname = strtolower($classname) . '.class.php';
// check for core class (should always exist)
if (file_exists(CORE_PATH . 'model/' . $this->loadclassname) and !class_exists($this->classname))
{
require CORE_PATH . 'model/' . $this->loadclassname;
} else {
$this->logError(SITE_NAME, CORE_PATH . 'model/' . $this->loadclassname . ' not found');
}
// check for an extended version
$this->loadclassname = strtolower($classname) . 'Extended.class.php';
if (file_exists(CUSTOM_PATH . 'model/' . $this->loadclassname))
{
$this->classname = $this->classname . 'Extended';
require CUSTOM_PATH . 'model/' . $this->loadclassname;
}
}
// similar methods for view and controller
I start at the controller level and load in required Models and Views.
$this->loadModel('Page');
$page = new $this->classname('PUBLIC');
$this->loadView('login.php');
never have to think about document paths, never have to write include/require⦠pretty simple and always reusable - at least for my applications.
Anthony is refering to the fact that you can add multiple autoload functions to a stack by using āspl_autoload_registerā this is handy if you are using libraries from different vendors with different schemes.
Autoload has its cost too and in most cases itās much greater than require_once - invoking a function, usually processing some logic in it and then require. Simple require_once is much faster in comparison. But I favour autoload for its convenience. There were discussions about how slow require_once is but after I did my own benchmarks I found the cost to be so small that not worth thinking about at all - at least less than invoking a simple function.
I havenāt used APC but have worked on hosts with eAccelerator and I didnāt notice any issues with require_once.
One thing Iāve done before, is iterating a directory structure (such as /library) and ārequiringā all files with a .php extensions. Itās a lazy way of loading all library files. The downside of course is that not all of those included files will be used. In fact itās likely the majority wonāt, so you incur a performance penalty as a result of having to load and parse files you wonāt use in that request. For that reason, spl_autoload is preferable.