I have a doubt about the right way/best practice about loading dependent classes in PHP.
I usually put all dependencies in the beginning of each class with a include_once in a way similar to Java imports. Something like:
include_once 'dto/SomeObjectDTO.php;'
include_once 'dao/SomeObjectDAO.php;'
include_once 'util/SomeObjectUtil.php;'
class SomeObjectService{
#class code here
}
This is the best way to load classes? Or maybe load all classes in a Bootstrap.php? Other ways?
Note that I'm talking about loading my own classes, not complex external classes like frameworks.
Like Homer6 said, autoloading is a php's built in dependency loading mechanism.
PHP-FIG proposed a family of PHP coding standards called PSR. PSR-0 deals with class naming and autoloading. Here are some links:
Requirements and an example autoloader
A good article on the subject
Also, keep in mind, that autoloading comes with a price. There is a lot of string work and work with the fs in the proposed default autoloader(you can implement your own faster autoloader, but it is not going to conform to the standard). This makes autoloading slow when you need to load a lot of classes. So if you needed to load 2 classes only, your approach would be faster and more understandable.
Since version 5.3 PHP supports namespaces.
This allows you to have a package and class hierarchy just like you know them from C++ or Java.
Check out those resources to learn more:
http://www.php.net/manual/en/language.namespaces.basics.php
http://php.net/manual/en/language.namespaces.importing.php
PHP's you can register your autoload method. Symfony 2 contains a nice class to do it with.
http://php.net/manual/en/function.spl-autoload-register.php
I've adapted it to work with the library that we've written.
https://github.com/homer6/altumo/blob/master/source/php/loader.php
https://github.com/homer6/altumo/blob/master/source/php/Utils/UniversalClassLoader.php
This adaption allows you to have namespaces that do not require the top level namespace to have the same folder name.
set_include_path(get_include_path()
. PATH_SEPARATOR . 'path1'
. PATH_SEPARATOR . 'path2'
);
// auto load classes:
function autoloadClasses($className) {
require_once $className . '.php';
}
spl_autoload_register('autoloadClasses');
Related
Problem
I am using the SPL Class Loader provided by PSR Group. However, I've come to a chicken-egg paradox.
That is, this will autoload classes preventing explicitly including them. But I first need to include/require this class and the code for instantiating the object
$classLoader = new SplClassLoader('Doctrine\Common', '/path/to/doctrine');
$classLoader->register();
Question
What is common solution for including the autoloader code?
In the case of a front-end controller, I could add the code there. But I'm not always using the front-end controller patter. I suppose I could also use PHP's auto_prepend_file. Interested in the communities input.
You explicitly require the autoloader on the bootstrap stage (the stage where the application is started up).
All subsequent functions/classes are then autoloaded.
Is it common practice to append use '.class.php' extension for PHP classes?
On PHP.net here: http://php.net/manual/en/function.spl-autoload-register.php there are some examples like this:
// Or, using an anonymous function as of PHP 5.3.0
spl_autoload_register(function ($class) {
include 'classes/' . $class . '.class.php';
});
which use a .class.php extension.
Should PHP code be written like this? I've never seen it before, is it something new? This is a kind of new feature in PHP so maybe it is?
EDIT: 'feature' was not a good word! Perhaps I should have asked whether it's some standard or convention.
Thanks.
It's not a feature, it's just a convention that you see come up every now and then. Whether to follow it or not is the choice of you and your team.
My personal opinion is that since the choice is arbitrary and this particular style contradicts with the PSR-0 autoloader specification you should pass because:
PSR-0 is more widely used, so all other things being equal it would be a better convention to follow
following the ".class.php" style means cannot take a PSR-0 compliant autoloader (there are many online) and use it without modifications
This is mostly used to assure its a class file the autoloader targets, you often have other .php files like templates, scripts like bootstrapping or config files that are .php files, but should never be interpreted as classes
It's not a feature as such, it's just a very simple, and practical way to keep your code organized and, more importantly, to avoid issues with autoloading.
Suppose you've got some class called User, and your site has a page, that is generated by a script: User.php. If you need an instance of the User class, the autoloader function will be called, and get User as an argument. When looking for a file simply called User.php, you might include a file, other than the class definition. That's why you can (and should) give class definition a little extra in their names. Then you can write your autoloader to look for [[class name]].class.php, neatly avoiding the User.php file.
That's the bottom line of it. There's -of course- also namespaces to consider, and that most modern way of all to keep your code organized: directories (set_include_path)
It is all for better understanding what this files all about. So, when you see filename.class.php, you know, this file contains Class filename.
There isn't any kind of special language support that gets triggered if you name your classes 'class.php'; it's just a convention, like whether you use spaces or tabs for indentation.
In one of the projects I worked on, classes where named *.inc.php, and templates *.tpl.php.
If I was coding php circa 1999, this would be an excellent convention to follow. You can name files whatever you want, but I recommend just naming them after the classname inside the file, with '.php' appended.
This is more of a personal preferences, but I would actually probably look into the PSR-0 standards which provide a standard way for you to name and namespace your classes to provide better compatibility with other peoples code in the same format.
In the PSR-0 standards PHP files are named after the class and put into folders related to the namespace.
I would recommend adopting this method over the .class.php method mentioned in the PHP.net manual.
I have been trying to learn about classes in PHP and part of my learning process has been looking at various libraries and stuff out there. Of course I am left with many questions, here is one of them.
When looking at some libraries, the main file that you call to invoke the library, they call each of the libraries files by invoking them directly by name, for example this is how the PHP chart library does it:
<?php
require_once 'model/ChartConfig.php';
require_once 'model/Point.php';
require_once 'model/DataSet.php';
require_once 'model/XYDataSet.php';
require_once 'model/XYSeriesDataSet.php';
require_once 'view/primitive/Padding.php';
require_once 'view/primitive/Rectangle.php';
require_once 'view/primitive/Primitive.php';
require_once 'view/text/Text.php';
require_once 'view/color/Color.php';
require_once 'view/color/ColorSet.php';
require_once 'view/color/Palette.php';
require_once 'view/axis/Bound.php';
require_once 'view/axis/Axis.php';
require_once 'view/plot/Plot.php';
require_once 'view/caption/Caption.php';
require_once 'view/chart/Chart.php';
require_once 'view/chart/BarChart.php';
require_once 'view/chart/VerticalBarChart.php';
require_once 'view/chart/HorizontalBarChart.php';
require_once 'view/chart/LineChart.php';
require_once 'view/chart/PieChart.php';
?>
However, I look at another library, and they just automate the process by calling each file in the directory using the PHP autoload method like this(From the php manual):
function __autoload($name) {
echo "Want to load $name.\n";
throw new Exception("Unable to load $name.");
}
I was just wondering if there is any advantage or disadvantage to doing it the autoload way?
I don't believe __autoload only has advantages. But there are some indeed.
Pros for __autoload
You don't need to maintain that long list of includes, which can be a pain to keep up tidy (which means there's no forgetting an include)
You only include what you really need: some classes might only be needed in some special scenario, you can avoid it
Pros for the normal way
It's very easy to understand for anybody
Looking at the includes will tell you what kind of things the file is doing
You control the list of classes you're importing (if you don't want a class because it's huge or doesn't work, it will never get included)
There's no complexity in the __autoload function. If your classes are in a complex hierarchy, you just need to type the name, and don't need to write complex code to find the correct file.
Easier to debug: the scope of the code that could be worrying is limited to the includes you did.
It's really a matter of coding style.
I think I would agree most with Cygal but would like to amend the response taking PSR-0 into account. I don't think it makes much sense using autoloading if you don't adhere to that standard.
Pro Autoloading
No need to maintain the include list.
You only include what you really need.
Code remains readable.
You follow a standard adopted by all major PHP frameworks so you can expect that people are familiar with this approach.
Pro old style
The dependencies are easily visible in the header of the code files.
There is no mapping between class names and file paths necessery. If you use autoloading a lot it might be necessary to reduce the time wasted for repeatedly calculating this mapping by using a cache.
To summarize: I don't see any reason to avoid autoloading as long as you follow PSR-0!
Using an autoloader is always advantageous.
You don't need massive collections of includes at the top of every
file
You don't have to worry about forgetting an include
Autoloader
only includes files that are necessary, and as they are needed
Potential drawbacks
Clash between your aotoloader and autoloaders used by libraries you want
Potential drawback can be avoided by registering your autoloader with spl
What Mark said. Also, you can keep your code DRY, if that's important to you.
The advantage if autoloading files is you don't need to worry about loadng the files yourself. And the files only gets loaded when they are needed.
An even better autoload function would be the newer: http://php.net/manual/en/function.spl-autoload-register.php
According to the PCR-0 proposal, all the autoloader needs is autoload() function. Zend has a few autoloading classes
Zend_Loader()
Zend_Loader_Autoloader()
Zend_Loader_Autoloader_Resource()
Zend_Loader_Autoloader_Interface()
I'm guessing it has all these classes because it's a framework, so it needs to load its own classes, as well as library classes for any libraries that the developer may add and which don't have their own autoloader.
I have a library (normal library, not a framework). Right now it doesn't have an autoloader so I use Zend's Zend_Loader_Autoloader_Resource ->addResourceType(). If I write an autoloader for it, which autoloader will be used: Zend's or the library? and do I have to implement an autoloader as complex as Zend's or a simple one like the PCR-0 example.
What happens in these cases
both framework and library have their own autoloader
framework has autoloader, but the library doesn't
framework has NO autoloader, and library has
I'd suggest sticking to direct path->class mapping and implementing your own autoloader like this:
class MyLib_Autoloader
{
public function __construct() {
spl_autoload_register(array($this, 'autoload'));
}
public function autoload($className)
{
if (substr($className, 0, 6) == 'MyLib_') {
include dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR strtr($className, '_', DIRECTORY_SEPARATOR) . '.php';
return true;
}
return false;
}
}
This will check if the class is from your namespace and load the file. Assumes your autoloader is in /some/path/MyLib/ -> the include path will be /some/path/MyLib/../MyLib/ClassName.php. You can also add more logic to strip the initial MyLib from the class name and get rid of that '..'.
Make sure to use only require. It's faster and the autoload function is not called more than once for each classname! :) No need to include_once/require_once/etc. Go with the fastest.
Usage is as simple as:
include '/some/path/MyLib/Autploader.php';
$loader = new MyLib_Autoloader();
The main question is : who/how will your library be used ?
If that is by you only, then use Zend's autoloader, this will save you time. You don't need to reinvent the wheel.
If you have to make you library public and used on different projects, then that may be a problem because it will force the users of your library to have Zend Framework too. So in that case, either you make your own autoloader, either you pick one of a framework/library but include it in your library (watch out for the licenses).
Now regarding the utilisation of the autoloaders : only the autoloaders that are registered will be called. If you have your own autoloader, but you didn't mention how to setup it in your documentation, the users of your code will never think of set it up, and then it won't be used.
So the basic answer is to say : use many autoloaders, register them all, and they will be all called and everything will work fine. But that may lead to conflicts, because one autoloader will try to load something that is supposed to be handled by another autoloader, so you have to be careful with that, and not abuse of them.
So I have an idea, but I'm thinking I need to run it by StackOverflow before I do something stupid.
I want to have an associative array of class names => filepaths. If PHP ever runs into a fatal error where the class is not defined, it will check if the key exists in my array and then require_once the class. This will prevent unnecessary bulk loading of classes that may never be used.
Bad idea?
How about trying PHP's built in autoloading.
Autoloading is the right way to do it, but spl_autoload_register is a cleaner way than __autoload, because it allows multiple autoloaders. Function __autoload also AFAIK stops working when spl_autoload_register is called, unless __autoload is also registered.
You can write your own autoload or use an existing one. For example, Zend Framework has an autoloader that uses conventions (Foo_Bar is in Foo/Bar.php). Nette Framework has RobotLoader, that indexes your classes and uses the index when neccessary. However, unless you use other things from the framework, it is probably too large.
see: http://www.php.net/manual/en/function.spl-autoload-register.php
If you are on PHP5, you can use __autoload().
makes your code a bit more manageable , although performance-wise, it's a bad choice. But I wouldn't worry it unless I'm building a Facebook.
What you are trying to do is already handled by the php __autoload function. You can read all about it here: http://php.net/manual/en/language.oop5.autoload.php
So, not a bad idea at all ;)
you should use autoloading with specified clas name structure, here is an example
the class names should should be only alpha and _ case-insensitive.
Lets take this directory structure and files
/classes/class.php
/classes/input/input.php
/classes/output/output.php
/classes/regex/regex.php
/classes/interface/parser/interface_parser.php
/classes/parser/parser.php
/classes/parser/xml/parser_xml.php
/classes/parser/html/parser_html.php
having the structure like this is good as it encourages you to code better when it comes to OOP.
Now if we take a look at the /classes/parser/html/html_parser.php file:
class Parser_Html extends Parser implements Interface_Parser
{
//looks nice in here
}
usually you would have to make sure the interface and the extended class is loaded, but these get autoloaded as well if they have not already.
creating the auto load system for this is not that complex, its just 1 function.
function __autoload($name)
{
//Classes
$parts = explode('_',strtolower($name));
$path = '/classes/';
foreach($parts as $p)
{
$path .= $p;
}
$path .= '/' . $name . '.php';
if(file_exists($path))
{
require_once $path;
}
}
so instead of including the class file first just run the class initiation.
$HtmlParser = new Parser_Html();
as the file has not been include the __autoload is run with a param of the class name, the autoload then looks in the directory that's relevant to the class name to try and load it.
also as your using the extend keyword in the class file shown above the class that is to be the parent gets run threw trhe autoloader aswell so you do not need to pre-load interfaces and classes etc.
Hope this helps you.
Note:
All code provided is untested and written for informational purposes, I would recommend you research the techniques more in detail before any implementation is done.