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!
Related
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.
This question already has answers here:
PHP include best practices question
(10 answers)
Closed 9 years ago.
What is the best practice for including PHP files?
Is it best to include a include.php file that includes all of the project PHP files?
Or to include it in those files that need them
Right now, my project has several include files in my index.php file. Does including all of my php files in the index.php make it less efficient?
Lastly, Where should one include the session check PHP file? in all of the PHP files?
EDIT 2016
Well, 5 years since I replied this. I am still alive. A lot has changed.
Now I use autoloaders to include my files. Here is official info for autoloaders with examples.
Basically, the idea is to have a proper folder structure (PSR-4 standards for instance) and having a class within each file. This way you can use autoloaders and PHP will load your files automatically.
OLD ANSWER
Usually, I have a config file like this:
define(root, $_SERVER['DOCUMENT_ROOT']);
.... // other variables that are used a lot
include (root . '/class/database.php');
.... // other includes that are mostly called from each file, like a db class, or user class, functions etc etc...
if (defined('development'))
{
// turn error reporting on
}
else
{
// turn it off
}
etc etc... You got the point of config.
And I include the config.php on each file. I forgot how to do it right now, but apache can do the automatic include for you. Therefore, you can say to apache to include your config file by default.
Then, I have controller classes, which call the views. There in each function I call the view.
someController.php
function index() { include root . '/views/view_index.php'; }
finally, from the view, if I need to include the header and footer view I do it like this:
view_index.php
<?include root . '/view/shared/header.php';?>
<div class="bla bla bla">bla bla bla</div>
<?include root . '/view/shared/footer.php';?>
I always use include in this structure rather than include_once since the latter requires extra check. I mean, since I am pretty sure that I include files only once, I don't need to use include_once. This way, you also know which include is where. For instance, you know that crucial files like db.php, or functions.php are located in config.php. Or you know that include views are located in controllers. That's pretty useful for me, I hope that helps you, too.
Using the include.php file is a very good practice according to me, as it is very helpful in changing the included files in big projects. If the project is small then including individual files is not a problem. But it becomes a problem to manage them as the project grows big.
For the session check file it is better to attach them individually as the requirement to check session on different pages might differ.
Including files individually or including them all in a single file and then including that makes much of the difference to the performance. As ultimately all the files are going to be included. It only becomes easy to manage them if single file is used to handle them.
I don't assume you are using object oriented programming but in case you do here might be a good answer.
In php you can define a function called the autoloader, if you try to create an object of a class that has not been defined the autoloader is called. You can then use the class name to figure out where the file containing that class is stored to include it at the last moment. Here is an example..
<?php
function on_load($class)
{
if(file_exists(require_once('classes/'.$class.'.php')))
{
require_once('classes/'.$class.'.php');
}
else
{
throw new Exception('Class not found: '.$class.' in classes/');
}
}
spl_autoload_register('on_load'); // tell php to call your on_load function if the class was not defined
If you're working on a big project you might want to group your files like this
/classes/database/MySQL.php
/classes/database/PDO.php // I'm just listing random stuff
/classes/Core.php // Whatever
/classes/datastructure/HashMap.php
You can then use a special naming convention to find the right directory
class Database_MySQL{} // look in <root_dir>/database/ for MySQL.php
class Core // look in <root_dir>/ for Core.php
class Database_Driver_Adapter_Useless_MysqlAdapterThingy {} // look in <root_dir>/Database/Driver/... blabla
Or you can use the php 5.3 way and define your classes like this
<?php
namespace database\driver\adapter\useless;
use database\driver\adapter\MysqlAdapter; // Now you have to tell PHP which version of MysqlAdapter class you want to use, even if there is just one
class MysqlAdapterThingy extends MysqlAdapter {}
Now you have to use the 'use' keyword in every file you need that class. The cool thing is that the namespace is automatically added to the class-name for your autoload function so you can do something like this
function on_load($class)
{ require_once('root/' . str_replace('\\', '/' $class)); }
If you want to learn more try googeling PHP auto-loading there is tons of information on this subject. But then again. From the format of you question I do not assume you're using OOP so this answer is just for the people who found this question on google.
Edit
I would also like to add the following:
// Only include the file once even if you place this statement multiple times
require_once('bla.php');
include_once('bla.php');
require('bla.php'); // Error if file doesn't exist, php will not continue
inlcude('bla.php'); // Warning if file doesn't exist, but php will continue
Using include or require without _once means that file will get included every time the statement is executed
Use include for template or user generated files, use require_once for classes
Just think easy, and think about load as less as possible and don't include something unnecessary.
So for your PHP files. if you include same php files on different pages just create 1 PHP file with this files in it.
If you use a PHP file in 1 page or 2 only, just include them seperate.
I hope i helped you with it ;)
Include files independently, use require_once() function instead of include, as require_once allow only one inclusion of file...
like
require "class.a.php";
require "class.b.php";
require "class.c.php";
class main{
function main(){
if(condition_is_met(){
$this->something = new A();
}else{
$this->something = new B();
}
}
}
Should the files be included in the condition check with require_once, and not all the time?
The question is not clear. In the current code, I think all of the file(s) will get included, whether you use (declare variable of these classes) them or not. If you wan't to not load the class(es) you will not use, you can use the __autoload() function.
http://php.net/manual/en/language.oop5.autoload.php
PHP has to open the file and parse it so it has some impact. For a few files I wouldn't worry about it but it can get out of hand as your files increase. That's why there's autoload, which allows you to load class files only when needed, without having a long list of requires at the top of your files:
http://php.net/manual/en/language.oop5.autoload.php
Also take a look at spl_autoload_register:
http://www.php.net/manual/en/function.spl-autoload-register.php
The only performance it should effect is the time to parse it, but I think that is preferred over complicated include logic hidden midway inside of your file. Not to mention that if you put the require inside of the if statement it is like you inserted that file's text inside of that if statement, which isn't right (and may not work).
Can anyone tell me if you can declare a class inside of a function/if statement?
Anytime you use include or require, PHP is basically copy/pasting the code from the required file into your code. So no matter where you put it, PHP is still opening the file, reading it and dropping it in there, it won't be affected by an if block. In other words, require is parsed before the code is actually run, so yes, you will take a (very small) performance hit even if require is put in an if block and never run. Keep in mind, this is a very small impact. Lastly if you are worried about it, I would use require_once - this ensures that this parsing does not happen twice, for example if a second required file requires the first file, this redundancy won't amount to a second performance hit.
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.
I've just started to build my very own MVC framework. Feel's kind of nice to know everything from the ground up and only get the stuff that's really necessary for my app.
I come from a codeIgniter background which helped me to get into the MVC perspective of seeing things. In codeigniter, to include a file, codeIgniters very own load class is used.
This load class, when loading a file, checks if a file have previously been included, and if not includes it, which ensures that a file isn't included twice.
However this method of including files has the downside of making it impossible (?) to run tests on my files or take advantage of PHPdoc in my IDE, which I need.
Clearly, I can use the normal include & require functions in PHP forwards and backwards across my application, where a certain library would be needed, but it clearly won´t be good to possible include the same file twice...
So - what's a good solution to use in my own PHP5 MVC framework to include files?
I'm doing a similar thing to you, and I'm using autoload.
Just put this in index.php:
function __autoload($class_name) {
include $class_name . '.php';
}
or include whatever logic you need to check multiple directories.
Edit: Here's my (slightly flaky) code for checking an alternate path. It could be done a lot more cleanly if you were going to need to check multiple paths.
function __autoload($class_name) {
$path = INC_PATH . strtolower($class_name) . '.php';
if (!file_exists($path)) {
$path = MODELS_PATH . strtolower($class_name) . '.php';
}
require $path;
}
just use include_once and require_once . while CI has a load class, you're by no means required to use it.
use include_once/ require_once but the best solution would be working with a autoloader
http://php.net/manual/de/language.oop5.autoload.php
what IDE do you use?
Generally php has the built in include_once which as the name says includes the file, but only once.
Or you can use autoloading which most IDEs support (though some need a bit of a hint - depends on what IDE are you using).