Is PHP 5's autoload inefficient? - php

When you manually include a PHP class you can do it while the current script is running, right? Then you can decide, if a condition matches you load it and if it doesn't you don't. Like this:
if ( $_SERVER['REQUEST_METHOD'] === 'POST' ) {
include '../../../Whatever/SanitizeUserInput.class.php';
SanitizeUserInput::sanitize($_POST['someFieldName']);
}
But let's say I use the autoload feature with this class. Will it be effectively loaded at the beginning or will it be loaded only if it's used?
I mean, should I add the __autoload function only in classes that I'm 100% sure I'm going to use in any script (e.g. database connection, session management, etc.)?
Thanks

Autoload is called only when you are trying to access desired class. And it would be better to use spl_autoload_register() instead of __autoload
Documentation:
You may define an __autoload() function which is automatically called
in case you are trying to use a class/interface which hasn't been
defined yet.
and
spl_autoload_register() provides a more flexible alternative for
autoloading classes. For this reason, using __autoload() is
discouraged and may be deprecated or removed in the future.

Autoloading kicks in when you are trying to use a class that has not yet been loaded:
include 'foo.php';
new Foo; // autoload not used, because the class already exists
// Bar is not yet loaded here, auto or otherwise
new Bar; // Bar is being autoloaded, because it was not yet loaded
As such, autoloading can be very efficient. It's slightly less efficient than loading classes by hand at the time when you need them, because of the overhead of invoking the autoload function. But keeping track of loaded classes by hand is more work for very little return over autoload.

Try it out, you will see, that whenever PHP stumbles over a class it doesn't know yet, it will call your autoload function. When your autoload function tells PHP in which file the class is, it will load this file.
To make the answer short, PHP only loads the file when needed, that is true even for conditions, so following test class will never be loaded.
if (false)
{
$test = new CTest(); // never loaded with autoload.
}

Related

PHP loading all classes on every page

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.

Using spl_autoload_register without using include

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.

php re-evaluate included files

I read about the class autoloading in PHP, but till now I didn't understand why we should use __autoload() method?
I read that
PHP doesn't use
this method becuase it has the handy little include functions,
include_once and require_once, that prevent you from loading the same
file more than once, but unlike a compiled language, PHP re-evaluates
these expressions over and over during the evaluation period each time
a file containing one or more of these expressions is loaded into the
runtime in this site why we should use autoloading,
but I don't understand what is the meaning of PHP re-evaluates in the above statement!!
why require-once don't solve the problem of loading php file more than once?
The original article is more clear when you read it more widely (see below) :
It simply says that __autoload() is smarter than include_once() because the function include_once() has to be coded explicitly when the class may be required, and also because this function needs to be processed each time it appears in order to know if the file given in argument is already loaded or not.
The other function __autoload(), on the contrary, can be called only once for several classes you may need. And then PHP tryes to load the corresponding source file only when a class definition is missing.
We can sum up this argumentation by saying: you need one include_once() for each Class/Function source, while only one __autoload() may be enough for a set of Class source having the same location rule.
Snippet of the article:
Why you should use an autoload function in PHP
The loading of classes is something that managed languages like Java
and C# don't need to worry about, class loaders are built into the
compiler.
[...]
PHP doesn't use this method becuase it has the handy little include functions, include_once and require_once, that prevent you
from loading the same file more than once, but unlike a compiled
language, PHP re-evaluates these expressions over and over during the
evaluation period each time a file containing one or more of these
expressions is loaded into the runtime. That is where the Standard PHP
Library (SPL), introduced in PHP 5, and the wonderful little _autoload
function come in to enhance the speed and uniformity of your PHP code.
__autoload is a magic function, that you define, that enables PHP to let you know when it doesn't have a class loaded, but that class
needs to be loaded.
The include_once statement itself is reevaluated whenever encountered.
for ($i = 0; $i < 100; $i++) {
include_once 'foo.php';
new Foo;
}
This will evaluate ("run") the include_once 100 times. That can be something of a slowdown. On the other hand:
for ($i = 0; $i < 100; $i++) {
new Foo;
}
When using autoloading, the logic for file inclusion will only be triggered once, the first time the class is needed.
but till now I didn't understand why we should use it
When you have structured and organized your work, because of the organization it results that you have many similar class files. The simpler example is an mvc, but not only, any custom structure will result in similar files containing a class, then because of the similarity you put them in the same folder and also you use a common file naming convention for example you can have a controller and a model directory.. check example file: employeeModel.php, statisticsModel.php, indexController.php, errorController.php
Well you can take advantage of this fact, check this customized autoload function:
/*** function to include model and view classes ***/
function __autoload($class_name)
{if(__DEBUG) eval(__DEBUG_EVAL);
/*** Load a model class ***/
$mfile=__SITE_PATH .'model/'.$class_name.'.php';//echo 'model file'.NL;v($file);
if (file_exists($mfile)){
include ($mfile);
if(__DEBUG) //store debug info before include
eval('error_log("autoload Success file exists: ".$mfile.NL);');
return true;
}
/*** Load a view class ***/
$cfile=__SITE_PATH .'view/'.'/'.substr($class_name,0,-4).'/'.$class_name.'.php';//v($file);
if (file_exists($cfile)){
include ($cfile);
if(__DEBUG) //store debug info before include
eval('error_log("autoload Success file exists: ".$cfile.NL);');
return true;
}
return false;
}
It also has a few lines for debugging that can easily be removed later. Because of similarity in things it can decide it self what to include and also to report errors when occur. Without this autoload function you would have to care that class files are availoable before use. Also this function will allow to include a file once, if you check carefully it does not use include_once, this means that autoload fires only when the file has not been seen before, in contrary to simple file inclusion which is fired every time the code is executed as very correctly decese notice it.
Conclusion Autload = fires once per file, automates things, so you execute a class directly without caring to include it.
Autoloading means if you need some classes to be included automatically in the scripts like
require_once ("class.user.php");
require_once ("class.module.php");
To avoid such code for each script you can use Autoloading functionality of php

Exception Based Class Loading in PHP

So I have an idea, but I'm thinking I need to run it by StackOverflow before I do something stupid.
I want to have an associative array of class names => filepaths. If PHP ever runs into a fatal error where the class is not defined, it will check if the key exists in my array and then require_once the class. This will prevent unnecessary bulk loading of classes that may never be used.
Bad idea?
How about trying PHP's built in autoloading.
Autoloading is the right way to do it, but spl_autoload_register is a cleaner way than __autoload, because it allows multiple autoloaders. Function __autoload also AFAIK stops working when spl_autoload_register is called, unless __autoload is also registered.
You can write your own autoload or use an existing one. For example, Zend Framework has an autoloader that uses conventions (Foo_Bar is in Foo/Bar.php). Nette Framework has RobotLoader, that indexes your classes and uses the index when neccessary. However, unless you use other things from the framework, it is probably too large.
see: http://www.php.net/manual/en/function.spl-autoload-register.php
If you are on PHP5, you can use __autoload().
makes your code a bit more manageable , although performance-wise, it's a bad choice. But I wouldn't worry it unless I'm building a Facebook.
What you are trying to do is already handled by the php __autoload function. You can read all about it here: http://php.net/manual/en/language.oop5.autoload.php
So, not a bad idea at all ;)
you should use autoloading with specified clas name structure, here is an example
the class names should should be only alpha and _ case-insensitive.
Lets take this directory structure and files
/classes/class.php
/classes/input/input.php
/classes/output/output.php
/classes/regex/regex.php
/classes/interface/parser/interface_parser.php
/classes/parser/parser.php
/classes/parser/xml/parser_xml.php
/classes/parser/html/parser_html.php
having the structure like this is good as it encourages you to code better when it comes to OOP.
Now if we take a look at the /classes/parser/html/html_parser.php file:
class Parser_Html extends Parser implements Interface_Parser
{
//looks nice in here
}
usually you would have to make sure the interface and the extended class is loaded, but these get autoloaded as well if they have not already.
creating the auto load system for this is not that complex, its just 1 function.
function __autoload($name)
{
//Classes
$parts = explode('_',strtolower($name));
$path = '/classes/';
foreach($parts as $p)
{
$path .= $p;
}
$path .= '/' . $name . '.php';
if(file_exists($path))
{
require_once $path;
}
}
so instead of including the class file first just run the class initiation.
$HtmlParser = new Parser_Html();
as the file has not been include the __autoload is run with a param of the class name, the autoload then looks in the directory that's relevant to the class name to try and load it.
also as your using the extend keyword in the class file shown above the class that is to be the parent gets run threw trhe autoloader aswell so you do not need to pre-load interfaces and classes etc.
Hope this helps you.
Note:
All code provided is untested and written for informational purposes, I would recommend you research the techniques more in detail before any implementation is done.

Any way to avoid loading unused classes for a non-oo app?

My application uses a 'central' page controller that grabs a bunch of files (I hesitate to say libraries) each containing a few related classes, using require_once, before fetching the request. As in:
require_once (dir_lib . 'db.php');
require_once (dir_lib . 'uuid.php');
require_once (dir_lib . 'data.php');
require_once (dir_lib . 'token.php');
require_once (dir_lib . 'logs.php');
require_once (dir_lib . 'time.php');
etc...
I haven't bothered to check memory usage until recently installing the (awesome, but gigantic) 'HTML Purifier' library and glancing at its autoloader. Apparently, autoloader on not, each script instance now weighs in at a whopping (sweet jesus!) 5376 kilobytes memory usage. (I have no idea what the built-in autoloader is for if that's the end result, but I digress) Without the HTML Purifier, most instances still weight in at over a megabyte.
Reading about the PHP autoload functions I'm getting the impression that the autoloader is meant strictly for OOP. With the exception of the purifier library, I'm using very little object-oriented code. Am I just misunderstanding the concept? Is there any other practical way to avoid blindly loading a bunch of classes that may not be needed for each request? Am I just being lazy for trying to include them all up-front?
EDIT -
Repeating this comment up up here to clarify what I meant by non-oo, if that makes much difference:
I am
basically using classes in lieu of
namespaces without using (hardly) any
actual OOP. That is to say, the
"DBFunctions" class may contain, for
example, the functions "execute" and
"getRow". The functions are invoked
with a static method call such as
"dbFunctions::execute($sql)."
Is there a particular reason for those function files to not be classes? The only one I can think of would be PHP4 compatibility, but autoload doesn't exist in PHP4 anyway.
Just wrapping those existing code files in class DBFunctions { ... } and prefixing your function calls with DBFunctions:: to match should be enough to let the autoloader go to work (after setting an spl_autoload_register() callback to suit), and it's worth it. It's still stylistically procedural if you wanted to keep the code that way, and a decent step towards OOPifying your whole code base should you want to go that way.
(And HTML Purifier is an elephant, have you checked out PHP's internal filter functions?)
Using Autoload shoudn't hit performance as the class them selves aren't loaded until they are called or used. Autoload contruct basically loads class as needed is they haven't been instanciated already.
Find in the code where the class is been instanciated first. Unless class files are instanciated automatically, it shoudn't take any memory. Maybe not all are been instanciated, but not unset when not needed.
When you find where each is been instanciated or the one in question you can use then:
//Gets the object name using the class.
echo get_class($classinstance) , "\n";
You can handle it by placing some break points, using memory_get_peak_usage().
//Output memory usage at start of class instanciation.
echo memory_get_usage()
#memory_get_peak_usage() prior to 5.2.1.
$classobject1 = new theclass();
//Output memory usage after class instanciation.
echo memory_get_usage()
Now try the same thing but this time using unset() after class have been used:
//Output memory usage at start of class instanciation.
echo memory_get_usage()
#memory_get_peak_usage() prior to 5.2.1.
$classobject1 = new theclass();
unset($classobject1);
//Output memory usage after class instanciation.
echo memory_get_usage()
So basically in theory, unset any unused instance across app, find large objects, debug.
This is to clarify #greg's comments regards OOP:
Take this chunk as sample:
class Tun{
private $run = 'i\'m running';
function run(){
echo $this->run;
}
}
echo Tun::run;
Output:
Error: Fatal error: Undefined class constant 'run' in C:\Work\pro\debug.php on line 16
The above sample because is referencing a function which uses OOP, in this case the class private variable $run. Since the class isn't instantiated(an object instance), it will error out. So, yes you can use functions inside of a class by reference but they mostly have to be plain procedural or constant references.
Hope this help.
PHP5's autoload is only for loading classes on the fly. Only one autoload function can be used in your application (but see below). Read the autoload docs for details. Basically, you can define an __autoload() function that will load any file you want (or do anything you want, for that matter), containing any classes you want, when PHP tries to call a class that isn't loaded yet.
The link that you provided in your question is about the Standard PHP Library's autoload, which is different, and more flexible. spl_autoload_register() lets you register a stack of autoload functions, rather than just one. This is most useful when you're using libraries in your code that make use of autoload, because their autoload doesn't have to clobber yours or those of other libraries.
If you're just starting out with OO on small projects, you probably just want __autoload(), but if you want to integrate libraries like HTMLPurifier, which does use spl_autoload, google for spl_autoload for the docs, they're the first results.

Categories