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.
Related
I'm building a website for a client, and he wishes to have a calculator for clients to calculate their monthly premium when they want to lease a car. This calculator appears in three different places in the website, so I decided to build it once, then include() the file into the main file. For instance:
case 'calculator':
case 'bereken-leasebedrag':
include('calculator.php');
break;
However, I have several classes defined in the main file:
use site\database\Vote;
use site\database\Vehicle;
use site\database\VehicleType;
use site\utils\ApiConnect;
use site\utils\Calculator;
And some more.
Some of these classes are used by the calculator file, such as Calculator and Vehicle and a few others. These classes are defined in the main file, but are not transferred to the calculator file, whereas variables like $_SESSION, $_POST and even my own defined variables like $car and $calc are available in the included file.
If I don't re-declare my classes at the beginning of calculator.php, it throws a fatal error in the page, saying it can't find, for instance, the class ApiConnect.
Am I doing something wrong here? Logically speaking, included files should inherit pretty much everything, and it seems counter-productive to have to specify every class needed for the included files.
I'm terrible at explaining things, so if I need to elaborate on something, I'd be more than happy to.
Thanks to deceze, I learned that use is used for aliasing, something I didn't derive from my Google searches.
Apparently the autoloader automatically includes all the classes we have, we just manually apply aliasing for every class. Which is kind of weird, but there you go.
Long story short, I had to either apply aliasing in the included file so that I could just say new Calculator(), or remove the aliasing and change every new {CLASS}() to new \{PATH}\{TO}\{CLASS}. I personally went with the first option, but if you have an autoloader and are running into thesame problem, at least you have a choice.
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.
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.
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
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.