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.
Related
This is my project path configuration
./create.php
/Install/Install.php
create.php
<?php
use Install\Install;
echo "Starting";
$install = new Install();
This gives me the error
PHP Fatal error: Uncaught Error: Class 'Install\Install' not found in /project/create.php:6
Install.php
<?php
namespace Install;
class Install
{
//whatever
}
Can someone explain me what is happening there ?
Obviously I guess that using a require_once line with my filename would probably fix the issue...but I thought using namespace and use import could prevent me from doing that like we do in classic framework like symfony / magento ?
I've seen some post speaking about autoloading, but i'm a little bit lost. Haven't been able to find a clear explanation on the other stack topic neither.
PHP compiles code one file at a time. It doesn't have any native concept of a "project" or a "full program".
There are three concepts involved here, which complement rather than replacing each other:
Namespaces are just a way of naming things. They allow you to have two classes called Install and still tell the difference between them. The use statement just tells the compiler (within one file) which of those classes you want when you write Install. The PHP manual has a chapter on namespaces which goes into more detail on all of this.
Require and include are the only mechanisms that allow code in one file to reference code in another. At some point, you need to tell the compiler to load "Install.php".
Autoloading is a way for PHP to ask your code which file it should load, when you mention a class it hasn't seen the definition for yet. The first time a class name is encountered, any function registered with spl_autoload_register will be called with that class name, and then has a chance to run include/require to load the definition. There is a fairly brief overview of autoloading in the PHP manual.
So, in your example:
use Install\Install; just means "when I write Install, I really mean Install\Install"
new Install() is translated by the compiler to new Install\Install()
the class Install\Install hasn't been defined; if an autoload function has been registered, it will be called, with the string "Install\Install" as input
that autoload function can then look at that class name, and run require_once __DIR__ . '/some/path/Install.php';
You can write the autoload function yourself, or you can use an "off-the-shelf" implementation where you just have to configure the directory where your classes are, and then follow a convention for how to name them.
If you want to Use class from another file, you must include or require the file.
Use require('Install.php'); before use Install\Install;.
If you are planning to do a big project I would recommend to use PHP frameworks rather than coding from scratch.
I would like to ask about php performance when you are about to require hundreds or thousand of files dynamically.
See script below
[Folders]
product (50 files)
user (20 files)
report (91 files)
each folder has a lot files but these files as classes. Example below
class cls_product_01 {
public $db;
function __construct($dbconn){
$this->db = $dbconn;
}
function saveProduct(){
//PS: the saveproduct.ext.php is a normal code (native approach)
require __dir__ .'/product/saveproduct.ext.php';
}
}
I have simple controller that will dynamically call the class based on the ajax params
$newAjaxClass = 'cls_'. $_POST['actionid'];
$newApp = new $newAjaxClass($dbconn);
I would like to require all the ajax file on each folder by looping.
Does this slow down the website since there are a lot of files?
PS: I am rewriting this code due to difficulty in maintaining code from the previous developer.
QUESTIONS: With that approach in mind will the application slows down if I load/required all files from the start this is similar to autoloading but I a bit hesitant if including a lot of files will slow down (eat a lot of ram) in the process. Especially I'll be including maybe about 300 to 400 files combined all folders.
I understand that using _autoload with make this easier since it will load the dependency dynamically. The big question is will using autoload with these a lot of script slows down the app? With that hundred of files how much RAM will the autoload eat?
You can use spl_autoload_register().
spl_autoload_register(function ($class_name) {
include $class_name . '.class.php';
});
http://php.net/manual/en/language.oop5.autoload.php
This is lazy loading and hence it won't include all your files upfront unless they are required.
For an example, if you were to load cls_product_01, calling:
new `cls_product_01();`
will look for the file cls_product_01.class.php and it will be included. However your case seems very cumbersome and I think you seriously need to consider your design again. And also I don't think it's a good idea to include files based on user provided data. [ like $newAjaxClass = 'cls_'. $_POST['actionid'];]
Hope it helps.
Check out autoloading.
http://php.net/__autoload
Basically if you tell it how it'll know where to find the file, given the class name, then you don't need to require them all up front.
I've seen a lot of threads here and in other forums that asked this a lot of times, but I still see using the include function of PHP in the answers?
how can I use this function, not using totally the include function?
Thank you
how can I use this function, not using totally the include function
You cannot totally not use include and that is not the point of using autoloader as you usually need to at least include the autoloader ;). That autoloader is the regular PHP code that is being called by PHP when unknown class use is attempted in the code. It is expected to include right file to make the class known, and the code continues as you'd explicitely include right file by hand in your code. So the main benefit shows up when your code uses classed (OOP) - you do not need to care if you included the class you are about to instantiate the object of or not. You just do new Foo() or call Something::methodName() and if all is set up right it will work.
The function spl_autoload_register is used to register a callback into the autoloader queue.
The PHP autoloader is a functionality of the PHP interpreter that, when a class is not defined, calls the functions registered in the queue, one by one, asking them to load the class, until the class becomes available. It the class is still not available after all the functions were invoked, the interpreter triggers a fatal error.
The autoloader doesn't perform any magic. It is the entire responsibility of the registered functions to make the class available. Most of them use the name and namespace of the missing class to figure out the path of the file that contains the declaration of the class and include it.
That's how the thing works. There are not many ways to produce a class in PHP and, for a reusable autoloader callback, the list starts and ends with include1 (include_once, require or require_once can be used as well but they don't make any difference in this case.)
The autoloader callback itself stays in separate file (for reusability) and usually that file also contains its registration as autoloader callback (the call to spl_autoload_register). All your code have to do is to include this file once in every file that is an entry point of your application.
All things being equal, your application needs to use include at least once and once is also the maximum required number of usages for it. The autoloader callback also uses include (probably also only once) but you don't write autoloader callbacks every day. If you wrote one and you wrote it well you can reuse it. Most people never wrote an autoloader callback and they will never write one.
Using Composer is easy and if you follow the PSR-4 rules of naming the files of your project, Composer can generate an autoloader for your project that knows how to load your classes (behind the scene it uses include, of course). All you have to do is to run composer init in the root directory of your project, run composer install and write include 'vendor/autoload.php'; in the file that represents the entry-point of your application. No other uses of include are required.
1 An autoloader callback is not required to include another file to make the class available. It can generate the code of the class on the fly and eval()-uate it, but the use cases of such approach are very limited. It is used by the testing suites f.e., to generate mock classes.
I have searched many blogs and websites but I didn't find any perfect answer.
whenever I use composer I have to include the autoload.php file and then for each class to autoload I have to use that class with the namespace.now I want to know what is the advantage of this composer where I can easily include the class file by include_once or require_once rather than using both autoload.php and the class file individually.
when I use composer I have to write these code:
include_once("vendor/autoload.php");
use namespace/derectoryname/classname;
whenever I include manually than
include_once("classname.php");
can anyone clear these?
First and foremost, composer main advantage is to handle dependencies (and your dependencies' dependencies, and so on). The autoloader is just frosting on the cake.
The question would be better posed as include vs autoloader, and then it gets slightly more interesting.
First, brevity. With one approach you'll end up using two declarations per file: use and include, whereas using the autoloader you'll just need to declare the use statements, and let the autoloader do the dirty work of actually loading the file.
Also, performance. If you include or require your requirement at the top of your file, you will always load that other file. With the autoloader, you'll only do so if you actually try to use the required class. Until you try to instantiate or use any of the required classes, the autoloader wont hit the filesystem and try to find the required class, making it more efficient, and only doing the work when you actually need the work.
As a somewhat crude example:
use Namespace\Package\Service\ServiceProvider
use Namespace\Package\Exception\ServiceProviderException
if (isset($options['service_id'])) {
try {
$service = ServiceProvider::getService($options['service_id']);
}
catch (ServiceProviderException $e) {
// do your exception handling
}
}
else {
// and now for something entirely different
}
With this, the file that declares ServiceProvider is only going to get loaded if you actually meet the requirements, and the file that declares ServiceProviderException only when if you have to catch the exception (although to be fair it would have been included by the autoloader when ServiceProvider needed to throw that exception, and not before).
On top of that, you've got a neater separation of concerns. Your ClassA that needs to use NameSpace\Package\ClassB is not required to know where you are actually storing that file. It's not its job, and shouldn't care about the actual structure of the filesystem, making the code more portable. Someone somewhere else might have a different vendor structure than you and still get use your code easily if it uses an autoloader, instead of hardcoding file paths in your require statements.
This should be more or less enough to show you that autoloading is a much more modern, efficient, and portable way to work than including your requirements manually.
And since you are already using composer to handle your dependencies, which is awesome, you get the autoloader benefits for free!
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