Autoloader converting namespace into folder path - php

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

Related

PHP - Using spl_autoload_register with subfolders

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.

how to manage includes and require_once in an effective way in php?

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

Using spl_autoload without use keyword on every page?

We have recently been rewriting our PHP application's model code using OO. We have the classes done, and we included namespacing (in the form of Project\Level1\Level2 or whatever). Since this is an already-built application, there are a lot of classes. We are using an autoloader, for ease of loading the classes, which is great. But here's where the hassle comes in.
We have probably 300 pages strewn all across the application, and all of them require a PHP file at the very beginning (a sort of bootstrap script). The autoloader script is required in that bootstrap file.
Now, most of our pages will be using at least one but likely many of the classes. We know that we have two options here:
//either call the classes using qualified names
$person = new Project\Person;
//or include the "use" keyword on every page, so we can alias the classes for ease of use
use Project\Person as Person;
$person = new Person;
But the hassle is that we would really rather not have to do this on every single page in our application:
require_once('../php/bootstrap.php');
use Project\Person\ as Person,
Project\Address\ as Address,
Project\Group\ as Group
Project\CustomField\ as CustomField;
$person = new Person;
$address = new Address;
We tried, for the heck of it, including the use keyword for all our classes in the bootstrap file, but according to the PHP manual, "Importing rules are per file basis, meaning included files will NOT inherit the parent file's importing rules."
It just seems like including these sprawling use statements on every page of our application is creating more hassle than it's worth. And what if we are using 15 classes on one page? Then the use statement would be huge.
My question is this: is it too much hassle? Are we correct in using namespaces, or is it not all that helpful in PHP? And now knowing what we are trying to do, are we doing it right? Is there something we are missing? Should we be calling classes with fully qualified names all the time or something?
(this is my first question on stackoverflow, so please let me know if I need to do anything differently or better with my questions in the future)
While using vanilla Zend Framework Autoloader might not be they way you want to go, the Zend Loader does support custom autoloaders, that can respect namespaces specified in-line or dynamically at run-time. In your case, you are using use Project\Person\ as Person which can become cumbersome, as you already noticed.
Using namespaces with the autoloader will allow you to take advantage of auto loading using simple path traversal to organize classes, without having to append large paths just to get to the interesting parts.
So, instead of new Corp_Assets_Generic_Person_Address, you could keep the folder structure and use new Namespace_Person_Address.
Namespaces avoid clashes in class names. Specially in large applications implementing autoloaders that need to load the right class from a number of different libraries. Using shorter class names makes the code easier to read but may make it harder to maintain. Adding the use statements makes it easier to read and later maintain but then it would be cumbersome to write and refactor. Documenting the expected behavior of the autoloader and using custom autoloaders to make more readable class names would be my suggestion.
In php.ini add your file as a prepend_file

__autoload vs include family

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.

Does the order of class definition matter in PHP?

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.

Categories