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.
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.
I have quite a few *.class.php files in my /classes directory. As the application is updated, these may change, more may be added, and some may be removed.
I have a file that is loaded every page load which includes all necessary files. Right now, I am doing this:
$files = glob($site->settings->root_path.'/classes/*.{php}', GLOB_BRACE);
foreach ($files as $file) {
require_once($file);
}
Is this much slower than specifying each file individually? Like:
require_once('/path/to/file1.php');
require_once('/path/to/file2.php');
require_once('/path/to/file3.php');
The reason I ask is because I think I remember something from a while back that led me to believe that iterating through files/folders was a painfully slow process, but I have no way of knowing for sure.
EDIT: If anyone has a better suggestion than glob, I'd be happy for the input.
Answering your question: yes, it will definitely be slower, just because you first have to get the list of files, and then execute require_once, that will make another access to file system to check if the file actually exists.
But this is a wrong way to do in my opinion. What you're trying to do is achieved with autoloading.
Basically, you have to define a function which will try to load a file from a file system, when a script wants to access a class that is not defined. This function then maps the name of the class (with namespaces) to a file on a file system and tries to load it. This way you don't have to worry about how many files you have in your folder, and how often they are added or removed.
Just to add to what's already here, the PHP documentation for autoloading has the following snippet (slightly edited however) which should fit what you're doing perfectly.
function my_autoloader($class) {
require_once 'classes/' . $class . '.php';
}
spl_autoload_register('my_autoloader');
If you, for example, have a class called ClassA in classes/ClassA.php, simply construct ClassA as you would if you had manually required it. It should work as it would otherwise. Hope that helps!
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
I download a framework and code and I have a question regarding require and include vs class_exists.
In the code I download, I see:
require_once('class.php');
As well as:
if(class_exists('class') == false) { require('class.php'); }
I get require_once means only 1 time and class exists check if the class exists.
My question is: is the second better than the first one? and why?
this condition:
if(class_exists('class') == false) { require('class.php'); }
prevent the require_once to be called.
require_once can be slow if you have a lot of files you include in your project (specially frameworks) because they have to scan the code to make sure the file is not included twice or more. so if you have over 25 file you include and they are nested, require_once will have to check all of them.
As discussed in other answers there are are semantic differences between the two variants. Also in a shared hosting scenario where the hosting provider isn't offering PHP Opcode caching (APC or equiv), all code files need to be read in and compiled once per request. Here the main killer isn't the compile time itself (~0.5M PHP statements / sec on a modern core) but the I/O overhead of collecting the PHP files if not pre-cached in the file-system cache (10s of I/Os / sec).
In this scenario if an application requires a core of say a dozen modules for 90% of queries then it makes sense caching a bundle of these into a single bulkload file. If this type of solution is adopted then placing a class_exists('class') guard around the require of the class file makes it bomb-proof.
Also a caution: If you use an __autoload() function to do JiT class loading, be aware that class_exists('fred') will trigger the autoload of fred. If you want a weak probe then you need to use the predicate !in_array( 'fred', get_declared_classes() ) instead.
The second one would provide more protection from importing the class twice. The first one imports the class file once, but if the class has been imported from another file for some reason the second will pick up that the class has already been declared earlier and not require the classfile.
require_once() only includes a file once.
class_exists() checks whether your class exists.
You can define a class in multiple files and require_once() will not care. Your second chunk will.
I currently am building my own PHP framework and am creating a lot of directories to store my classes in.
This is my current autoload function:
function __autoload($className)
{
$locations = array('', 'classes/', 'classes/calendar/', 'classes/exceptions/', 'classes/forms/', 'classes/table/', 'classes/user', 'pages/', 'templates/');
$fileName = $className . '.php';
foreach($locations AS $currentLocation)
{
if(file_exists($currentLocation . $fileName))
{
include_once ($currentLocation . $fileName);
return;
}
}
}
Now in my main class file I do have all of the necessary classes already included so that they won't have to be searched for.
Here are my questions:
Is this function efficient enough? Will there be a lot of load time or is there a way for me to minimize the load time?
Is include_once() the way that I should go about including the classes?
Is there a way that I could write the function to guess at the most popular folders? Or would that take up too much time and/or not possible?
Would namespaces help me at all? (I am reading and learning about them right now.)
This is answered very well here: autoload and multiple directories
You should probably go with require, for two reasons: a) you don't need to have PHP track if the file has been already included, because if it has it won't need to call __autoload in the first place and b) if the file cannot be included you won't be able to continue execution anyway
The answer for point 1 covers this
Not necessarily; you need some namespace-like mechanism to implement faster loading (to only look where you have to) but you can fake it if necessary without using real namespaces
For reference, the interaction between __autoload and namespaces is documented here.