I've discovered the __autoload function today and after reading the official manual page of this function there's a point I don't get at all.
What's clearly the difference between using __autoload() and let's say require_once?
because it looks autoload is the new fashion way of doing the required includes but to me it's far better to use require_once instead. Hence, __autoload has to be defined into all the php files which means writing its code down there, if I put ALL my includes/require_once/...etc into one file let's call it main_header.php then all I'll need to do in my web app files is write one line of code:
<?php require_once('main_header.php'); ?>
Am I wrong somewhere?
I can see two things going for autoloading (not necessarily __autoload; prefer the more modern spl_autoload_register instead):
You don't need to explicitly include the classes. Of course, you could make a main_header.php as in your example, but then the next item comes into effect.
You don't have to load 100 classes if you are only going to use 10 of them.
It's also worth to point out that autoloading is also triggered when unserializing an object of a class that has not been yet defined, which makes things infinitely more practical. Of course there is another hook in unserialize for this (the configuration setting unserialize_callback_func), so autoloading is not technically necessary. It's definitely nicer though.
First: Use spl_autoload_register() instead of __autoload().
The autoloader is called, when you try to access a class, that doesn't exists. With include() you just include a class. The main difference is, that using an autoloader the class is only included, if its really required/used.
Usually you define an autoloader in one file and include this one on every request. If you use bootstrapping (meaning: a single file, that catches every request and redirects it to the appropriate target) its only required to define the autoloader there. So its its not required to define it in every file.
Autoloader is used for lazy initialization. It's the most effective with MVC architecture, not with websites that include a file here and there and define db connection string in every file (which is terrible).
Using autoload with MVC framework saves resources and brings a lot to modularity. Since you don't have to include files with classes, you just instantiate a class you require in the controller you're currently at.
Basically, it's an OOP thing. You shouldn't worry about it if you're not using object approach to structuring your website and include/require is what will work for you.
I think it comes down to personal preference. For me, autoload is a typical php kind of thing - a dirty "magic-quotes"-alike hack, that only exists because they don't bother to sit down and code a clean solution to the problem - in this case, an adequate packaging system + a catchable ClassNotFound exception. Until we've got this fixed, I'll stick to include.
Choose the right tool for the job. Autoloading is for loading the source-code of yet undefined Classes prior use. So you can instantiate classes you have not required the files for so far.
This makes sense if you work with classes and you want to require files at a central place, a single point instead all over in different files.
But if you're using includes and requires to let's say build a website with menu and footer, this does not make sense. Autoload does not work for this:
<html>
<head><title>Reciepes collection - My Homepage</title></head>
<body>
<?php include('header.html'); ?>
<h1>My Reciepes collection</h1>
<p>Cooking is one of my favorite hobbies .... (</p>....)
<?php include('footer.html'); ?>
</body>
</html>
If you're making use of requires to load functions, you can not use autoload either.
So only because autoload looks somewhat fancied by others to you, it does not mean that it fits your needs.
I personally use it in projects where I do not want to take care of the requires for classes and where I want to be able to dynamically load classes from within a modular directory and library structure.
I only make use of spl_autoload_register() to register one or more autoload implementations. It's the recommended method to register an autoload function in PHP as it allows to have multiple autoloaders.
All the answers are more than correct and adequate. I just thought I should add my two cents.
First, *_once functions are slow. Do not use them.
Secondly, in an app I am developing, I have lots of classes which I rely on each other and I do not always know which classes are needed in a page.
Instead of creating a main.php page and including all the classes which are a lot; obviously wasting resources and time (Include and require are expensive), I use autoload to include those files as and when they are needed by the page.
All I do therefore is code and the classes are added automatically.
This also improves your code and directory structure since you follow a system in naming your classes and files.
Just an addition. In terms of resource usage and speed(decreasing order of requirements and increasing order of speed):
Require_once() ; include_once() ; require() ; include()
Making include the best and fastest.
Autoload and the include family functions both have their place.
Autoload is intended for lazy loading of modules in an OO based script (namely classes and interfaces) and is invoked when you use new or statically call a method of a class that hasn't yet been loaded. This triggers autoload to run a function that attempts to load (typically via include) the class or interface in question. The advantage of this approach is that classes are only loaded as and when they are needed. Any class that doesn't get used doesn't get loaded.
Autoload cannot be used for loading program fragments that aren't a class or an interface, for those items you still need the include family.
As for having to add an autoload function to every script that needs to autoload? In this case you put the autoload function in its own file and include it in the scripts that need to autoload. :)
Another note: include and require may become a big pain while unit testing.
I don't know how should I prevent requiring / including anything. There is test helpers, that can do some useful things, such as preventing exiting or dieing, but they still cannot mock include or require.
Mockery library recommends using autoloading to be able to mock public static methods.
Related
So I am using spl_autoload_register to load my classes. However I have this structure for my classes:
classes
classfolder
classfile
So normally when I was including them I was doing this:
include('classes/modules/module_class.php');
Now using spl_autoload_register how would I handle sub folders? I dont have the ability to upgrade to php 5.3 to use namespaces, do I need to do something like this?
$module = new modules_Module();
Then the function I register with spl_autoload_register explodes the _ and uses the first part as the class folder and the second part as the class method. But then I would have to change the class name to modules_Module right? If so is that ok? Or is there a better way of doing this?
Not saying you should do that, but a common pattern in PHP-land is to use case in the filenames as well and not add stuff like _class or class.Module.php:
include('classes/Modules/Module.php');
In PHP 5.2 (no namespace support), you then work with the _ underscores:
class Modules_Module
{
}
So this is how it is normally done. Not saying that you must do it that way. You can also just resolve as you wish. But one should also know about this more common pattern as it helps reading/navigating third party sourcecode.
Basically that's it.
In addition to namespaces (which you can't use) and naming conventions on class names (which would need you to rename all your classes) the only other sane option is to build a classmap: an array that maps class names to the full path of the file that defines them.
Going this way means that you have to update the classmap each time classes are added or modified, a task which is a prime candidate for automation. Look into using Composer's autoload functionality, it can do this on demand and generate the autoload code for you automatically. Composer is so good that it's useful even when you disregard 90% of its features.
As long as your files are arranged in some way that let's you go from the class name to the file name, you can implement your autoloader function however you like. Your autoload function needn't just turn the class name into a directory path: it's job is simply to take a class name, and include the right file, if at all possible.
Keeping your mapping relatively simple is useful for humans, too, though - so you know which file to edit.
For instance, you could say that all classes beginning Mod_ live in a directory called classes/modules but all others live in a directory called classes/general.
You can also use file_exists to check multiple possibilities for one class, but bear in mind that this has some cost, both to PHP checking the filesystem, and to the human trying to remember where the file went.
I have some defines in my index.php, with values pointing to some folders. I want to avoid the anoying requires:
require_once("something/../../../file.php")
The problem (because of the scope) is that Those defines are lost when I try to use them in another php file, then I need to make again require_once("/../../......etc"), or define them again.
How can I avoid this to have something like:
require_once(PATH_LIBRARY1."/my_file.php")?
You must learn about autoloading.
It helps to avoid of using require or include at all.
About psr-0 standard.
It helps manage your classes in file system correctly. And use simple autoload function.
About composer.
It helps to avoid writing of anything for autoloading. Even if you are not using psr-0 it can create class map.
In modern PHP applications the need for require/include is very small because the most effective way to include code is to use OOP classes and the autoload feature. That way you never have to worry where the code for any class is located, you simply use the class.
The only things that still need to be included manually are functions outside of classes and things like configuration arrays that also do not define a class themselves.
A few choices:
Use Autoloading
Define a base path constant for the application and rely on that
Define a central library that's responsible for loading the classes you need
In my project structure I have the usual class per file separation and auto-loading is easy, but now I would like to group some small classes in a a single file, probably a file with the name of the current folder.
now:
|/module
|-Smallclass1.php
|-Smallclass2.php
|-Smallclass3.php
|-Normalclass.php
after:
|/module
|-module.php <-- smallclasses go here
|-Normalclass.php
Now comes the debate.
To autoload one 'SmallclassX' I was thinking to check if SmallclassX.php file exists if not check if module.php exists and if so, check if the class exists inside the file and include it. Including the whole module.php file when I need a single class seems an overhead specially if the file contains many classes. Here they suggest using tokens the check if the class exists, but I'm not sure about it's efficiency, after that I'll need a method to include only the class I need.
Do you think if I get to load only the class I need like I mentioned, will it be also an overhead because of reading the file more that once and looking inside to include the piece of code I want?
You can stack autoloaders using spl_autoload_register, allowing you to first attempt to load the class from a dedicated file, then falling back to including the module file afterwards (and if no autoloader can solve the dependency, error out normally). This will allow you to avoid all hacks by parsing tokens and other items, which will require a lot more than just require-ing the file and seeing what the result is afterwards.
I would however advice you to benchmark this solution. Whether it's more effective will depend on the delay for accessing the files (APC) and the cost of parsing and including each class seperately.
I'll also agree with the other comments, it might be confusing that you have two separate schemes for including classes, and APC will remove most of the cost of having separate files anyway.
Is it good to use an autoloader that load root/app/model/test.php when trying to use App\Model\Test? In this way every class should be organized accordingly to its namespace.
Is this a good approach? If not, why? what would you suggest?
Should I define a specific array namespace => path that will assure that we are not loading an unexpected file? this way I would have to set every time something like $map['App\Model\Test'] = 'root/app/model/test'; and this would basically delete all the fun of autoloader. Isn't it?
It is a rather "standard" approach used in OOP
Usually autoloaders are faster when they have a classmap ($map) injected into them. This is because they don't have to run through the include paths to look up the file with the class being instantiated. Give them an absolute file name, and you'll decouple them from the include path. Providing a $map also allows you to organize your classes in another fashion (not just filesystem-based naming). Apart from this, there are also class map generators that you could run before to actually achieve this and not have to (re)do it by hand each time you rename or move some class. During development, however, it is more convenient to use the standard autoloading logic (no classmaps), because keeping in sync files and the classes declared in them can get quite tedious and have little do with development itself.
Reducing the number of boilerplate code is not the only purpose of the autoloader:
you load only those class declarations that are actually needed in your code; not all or some declarations; only those that are used
it ensures your include_once and require_once in respect to classes happen only in autoloading
your classes don't focus on loading files; they focus on their function
If I have several classes in different php files that I'm including into a single file, and some of these classes have dependencies on other classes, does the order in which they are included matter? Or, is simply including them (in any order) before they are used all that matters?
Yes, it matters. This is mentioned as a note in object inheritance documentation:
Unless autoloading is used, then classes must be defined before they are used. If a class extends another, then the parent class must be declared before the child class structure. This rule applies to classes that inherit other classes and interfaces.
I recommend to use autoloading to resolve class dependencies. That way classes are only loaded when they are actually needed and you don't have to bother with including every single PHP file by hand.
You have to keep every class in it's own file for this to work, though. But that's a good way to keep everything tidy and clean, anyway.
Within 1 PHP file, you can declare functions/classes anywhere and call them anywhere (within that file), order does not matter.
As for includes, you must include the file BEFORE you attempt to use a declared function/class within that file.
Simply include them before they needed and everything will be fine.
It would matter as if one class tried to use another which had not yet been parsed, then an error would occur. The best option is to place the classes in the script so the dependancy will still be intact.
If they all are in the same file, no the order shouldn't matter. There are some rare instances (I've seen with namespaces) where the order does matter, but don't worry about that too much unless you're pushing the envelope.
Try it. The worst that can happen is that it'll give you an error...
Yes it does matter and when a large number of classes are involved, it can cause problems. Using autoloading is not feasible when your production scripts needs to include 40 or 50 classes, which is always the case if your application is properly designed in accordance with best OOP practices, and you need to deal with forms etc...
Let me explain why the order matters. If you use an autoloader, every time the keyword extends is found, there is an attempt to autoload a class. So if you extend before the class being extended has been defined, it will trigger an autoload event.
When you develop your application, use a custom autoloader. Make that custom autoloader give you information about timing and memory used. It will load all class files one by one and waste a lot of time doing so. When your application is finished, you can optimize by concentrating many related classes into one file. For example, my form class is in class.form.php and it does not just load the form class. It loads another 50 classes related to forms. So I have everything in one file and when I create a new form(), the autoloader loads class.form.php which include the other classes that a form usually need (form_checkbox, form_input and so on) so when they are needed, they are not autoloader because they are already defined.
You can create a PHP script that will recurse, resolving dependencies and order all your classes within the single class file (class.form.php using my example) so that they all have the parent class defined before the extends keyword (which triggers autoloading) is found. I run php -w on the concatenated file which strips comments and spaces. It has reduced my form classes from 80K to 18K. Whenever I use a form, I create a new form() and it loads 18Ks worth of form-related classes, which is not excessive.
Initially I used the linux command cat but it does not work. You need a smarter script that can resolve the parent of each extended class and properly order classes in the file that contains many related classes.