I'm trying to start using SPL Autoloader but I can't seem to grasp its importance yet.
Lets say I have a directory "classes" with sub-directories and php files in them as classes as follows.
'classes/feed/feed.php';
'classes/compose/file_upload.php';
'classes/compose/char_limit.php';
'classes/feed/postrank/postrank.php';
'classes/notifications/push.php';
Then I create a PHP file called autoloader.php inside "classes" directory with includes as follows
<?php
include_once 'feed/feed.php';
include_once 'compose/file_upload.php';
include_once 'compose/char_limit.php';
include_once 'feed/postrank/postrank.php';
include_once 'notifications/push.php';
?>
Then on every page where I want those classes I just include the autoloader.php file to include all classes of the project.
1. What problems I'm I going to face as the project grows?
2. If I were to start using SPL Autoloader how would I set it up with my current directory structure?
3. Is there a difference in loading time between using include/require compared to SPL Autoloading ?
4. Should all the classes be under one directory "classes?" or there's no problem with my file structure?
1. What problems I'm I going to face as the project grows?
You'll have to include more and more files in your autoloader.php. Plus, you'll have to include it in your every new file. More file reads. Less performance.
2. If I were to start using SPL Autoloader how would I set it up with my current directory structure?
Directory structure doesn't matter (assuming your classes tree is arranged nicely and logically). What matters is the namespace you specify inside your class. For example, if you want SPL to auto-load a class containing in your classes/feed/postrank/postrank.php file (a postrank class declaration, presumably), this file has to have a namespace declaration inside it, e.g.:
namespace classes\feed\postrank;
class postrank {
...
}
This way SPL would know how to find the declaration of the class in your application's file system.
3. Is there a difference in loading time between using include/require compared to SPL Autoloading ?
If you include everything in autoloader.php, you force PHP to read and include every single file in there. SPL only loads the classes you need, and only when you need them. The time difference could be noticeable if you have a decent number of files and classes (say, hundreds of them), depending on your application server performance.
4. Should all the classes be under one directory "classes?" or there's no problem with my file structure?
Depends on your application structure really, so it's entirely your call.
Related
I'm building a website and are getting more and more classes to load. Currently I'm including every class in index.php and I also have a ajax handler where every class is included, so I basically include all my PHP files at ajax calls and on every page on the website.
Is this bad practice?
I've tried searching a bit around an have seen that there is a function called spl_autoload_register. By reading a little about it, my understanding is that it tries to include the files defined if a class is not found. But, how is that different from require_once or include_once.
Lets say I have the class underneath in a file and then use require_once('myclass.php');
class Myclass {
function myMethod {
//some code here
}
}
But, the class is not in use before I initialize it with $class = new Myclass; So what is now the difference from running
function my_autoloader($class) {
require_once('classes/' . $class . '.php');
}
spl_autoload_register('my_autoloader');
I would still have to initialize it with $class = new Myclass; when I want to use it. Are there some performance gains from either of them or is it more a preference thing?
And one more question. Should PHP be minifyed like its done with JS and CSS or is this pointless with PHP?
In 2018 the best way to work with autoloading is Composer - build for easy work and performance optimization.
4. Steps to Load Your Classes Fast and Clean
Download composer (for start even right to your project, it's up to you)
Create composer.json and tell him directories or files to load classes from:
{
"autoload": {
"classmap": "/src"
}
}
Using most open and friendly classmap option.
Rebuild cache by CLI command:
composer.phar dump
Include it in index.php
require_once __DIR__ . '/vendor/autoload.php';
And you're ready to go!
The code will technically run faster if you don't load every file on every page, but this will largely go away if you configure "OpCache", which loads all the compiled class definitions into shared memory. And at some point, you may end up with a page that needs 90% of your code loaded to do its job anyway. (This is also relevant to your question about minification - PHP is compiled on the server, so minification doesn't really help anyone.)
The other advantage with autoloading though is maintenance - when you define a new class, you don't have to add it to some master-list of includes, make sure it loads after its parent class but before its child classes, etc. Instead, you place the class definition in a meaningfully named file and directory (great for humans finding it too!) and the autoloader will find it when it's needed.
I did extensive measurements on TYPO3 (PHP) including hundreds of class files on a machine with SSD. I created a script including all available classes. Class reading was not a very expensive part compared to other issues.
I would focus on this optimisation, once all more important questions are addressed.
Many developers writing object-oriented applications create one PHP
source file per class definition. One of the biggest annoyances is
having to write a long list of needed includes at the beginning of
each script (one for each class).
In PHP 5, this is no longer necessary. The spl_autoload_register()
function registers any number of autoloaders, enabling for classes and
interfaces to be automatically loaded if they are currently not
defined. Source: http://php.net/manual/en/language.oop5.autoload.php
Well i found that this statement is not true, because i still end up writing
long list of includes imports in each file simply because i am using different sub folders inside my includes folder and namespaces according to PHP-FIG's PSR-0 coding convention.
includes/core/database/
includes/core/html/
includes/domain/
etc.
spl_autoload_register() unable to automatically load DB, HTML Domain logic classes because it does not know folder structure where file is so i am using namespaces to it, but it takes just as much space as having imports on top of every script.
use MyProject\Core\Database;
use MyProject\Core\Html;
use MyProject\domain;
I use different classes per script so i cannot simply make one big file and include_once(), besides importing of namespaces does not work with include_once().
I instantiate class like this
try {
$DBQuery = new Database\DBQuery();
$HtmlGenerator = new Html\HtmlGenerator();
$domain = new domain\UserRegister();
} catch (Error $e) {
echo $e->getMessage();
}
My Autoload function
spl_autoload_register(function ($fullyQualifiedClassName) {
//change backslash in namespace name to DIRECTORY_SEPARATOR for file system
if ( stristr($fullyQualifiedClassName, "\\") ) {
$fullyQualifiedClassName = str_ireplace("\\", DIRECTORY_SEPARATOR, $fullyQualifiedClassName);
}
//function dirname() used because THIS file in sub folder /includes and we need to go to parent folder
$class_path = $lib_patch . DIRECTORY_SEPARATOR . "{$fullyQualifiedClassName}.php";
if ( !is_file($class_path) ) {
throw new Error("Unable to load class with path: $class_path");
}
require_once $class_path;
});
Any way i can avoid importing multiple namespaces at this i am open to stopping using namespaces completely but i'd like to keep my sub folder structure. Is there way auto-load function can know what folder my files at without making code that will loop trough every sub-folder looking for file e.g. DBQuery.php because this will impact performance.
Autoloading is saving you from includeing the files, you're now exclusively dealing with name resolution. If you don't want to write a bunch of use statement in your files, you could simply use the fully qualified names of those classes instead of aliasing them:
$db = new \MyProject\Core\Database;
$html = new \MyProject\Core\Html;
...
The use of use MyProject\Core\Database is that it enables you to write Database instead of \MyProject\Core\Database. Autoloading of the underlying file works the same.
If you even don't like that aspect, then it's hard to have your cake and eat it too. You could flatten your namespaces so you don't have as many different namespaces to import, but then your project organisation starts to become more prone to name clashes or harder to locate files. It's a tradeoff, something has to give somewhere. If you're not happy with some consequence of using namespaces, you need to find a new happy middleground for yourself.
Having said this, in many languages it is extremely common to have a bunch of import statements at the top of each file in one way or another. A decent IDE can largely auto-generate those while you write your code. It is something that you should rather get used to instead of fighting against it. It may be annoying, but the alternatives are more name clashes or giant imports. It's virtually impossible to have it modular, fast, extensible and terse all at the same time.
This is what I have at hand:
//Person.php
namespace Entity;
class Person{
}
User file:
//User.php
use Entity\Person;
$person = new Person;
Here, it fails if I don't include the Person.php file. If I include it, the everything works fine. Do I absolutely require to include the file even when using namespaces? If at all we need to include/require files, then how can namespaces be effectively used? Also, can we maintain folder structure by nesting namespaces?
The answer to your question is "yes and no".
Indeed the code implementing class Person has to be included, otherwise the class is not defined and cannot be used. Where should the definition come from, when the code is not included? The php interpreter cannot guess the classes implementation. That is the same in all programming languages, by the way.
However there is something called Autoloading in php. It allows to automatically include certain files. The mechanism is based on a mapping of class names to file names. So in the end it boils down to php searching through a folder structure to find a file whos name suggests that it implements a class currently required in the code it executes.
But don't get this wrong: that still means the file has to be included. The only difference is: the including is done automatically, so without you specifying an explicit include or require statement.
Yes, you need to include every file.
A very good example can be found here on effective usage of namespaces.
With PSR-0 autoloading, the namespace has to be the same as the folder in which the class is, file the filename has to be the same as the classname. This gives you very simple and effective autoloading with composer for example.
I have a list of files, wherein a file is inherting another file ion the same directory. I want to include all files of a directory, how do I do it in the order of inheritance so that I dont get any errors
Instead of calculating dependencies yourself, you might as well use auto loading using spl_autoload_register().
This way your dependencies get worked out as required. A bit like "Just-In-Time" loading :)
If your file/s have certain dependencies on other files, make sure you include the "parent" file/s first.
For example, you have a class A in a file A.php:
<?php
class A {
// .. statements
}
And you have a class B that extends A named B.php:
<?php
require_once( "A.php" );
class B extends A {
// .. statements
}
The idea is to "include"/"require" the needed files first prior to using any functions/classes/statement in that file. In PHP 5, you can use the auto-loading functions that would "automatically" add/include the file you need without the constant need of typing require functions.
You COULD use a parser to chek for dependecies but this would be a awfull lot of work and a real performance killer.
You could sort the files and prefix them with numbers
001.init.php
002.db_connect.php
003.pre_filters.php
But if you sort them manually it is rather pointles to rely on the file names.
If you have class inheritance you can combine a autoloader and require once.
Register an custom autoloader to require fles using require_once and and include all your files with a loop. If you need a class from the 8th file in your 4th file the autoloader will load the 8th file ahead of time and when your inlude loop reaches the 8th file nothing will happen because require_once will not include the file again.
But as you might already have realized:
Including files which are depending on each other in a random order from the file system is NOT a good idead.
In PHP are classes only seen when they are in an include file? In Java I can see them in another file without including that file in my current file. In PHP is the only way to see any given class to include it in your file? So I'm just including my class file(s) everywhere?
In PHP are classes only seen when they are in an include file?
Yes. However, in PHP 5, there is the new Autoloading feature that allows you to build a function that includes a file when a class name is invoked. That effectively makes it possible to auto-initialize classes.
The simple example in the manual (I extended it slightly) makes it clear how this works:
<?php
function __autoload($class_name) {
require_once $class_name . '.php';
}
$obj = new MyClass1(); // Autoloader will load "MyClass1.php"
$obj2 = new MyClass2(); // Autoloader will load "MyClass2.php"
?>
Advanced autoloaders like Zend Framework's Zend_Loader_Autoloader (and the Standard PHP Library's spl_autoload_register(), cheers #ircmaxell) make it even possible to add different autoloading rules for different prefixes, allowing for libraries to be loaded from varying directories with varying naming conventions.
Generally speaking, yes. However, do note that includes are cascaded--in the sense that: if you include file a.php which includes file b.php, you can now see file b.php in your current file.
Also, PHP 5 offers Autoloading Classes which I recommend you take a look at:
http://php.net/manual/en/language.oop5.autoload.php
Yes -- PHP doesn't have any visibility into code which wasn't included directly in the file using the code.
However, instead of including (or the preferred method -- requiring) .php files everywhere, many developers choose to use the PHP autoload ability (http://php.net/manual/en/language.oop5.autoload.php) to automatically load the required file when you use a particular class.
Yes, for a class in a file to be available, that file has to be included.
Including a file can be done in a number of ways, either using the following functions:
include(filename);
include_once(filename) - which only includes the file if it's not already loaded
require(filename) - equal to include, except that the script will halt if file is not available
requier_once(filename)
Files can also be autoloaded through the __autoload or spl_autoload_register functions. More info on autoloading classes on PHP.net.
Yes only in include statements will you have access to the functions in other php files. PHP is by standard a Procedural language. It works from the top order down, so if you wish to perform class like includes look at Object Oriented PHP or include the files at the top of the php page.