In my include_path on the server-side I have a reference to a pear directory, in '/usr/share/pear/'. Within my applications I include files from a common library, living in '/usr/share/pear/library/' with require_once 'library/file.php'.
I've recently started using the spl autoloader, I noticed in the loader function you have to determine the logic with which to include the file. My first way of doing this was trying to include a file and suppressing it with # to see if it would fail, e.g. #include 'library/file.php' however I think mostly because I read a lot about # being a bad practice I decided to manually do the work myself by exploding get_include_path by the PATH_SEPARATOR and seeing if the directory is what I want it to be, then doing a file_exists and including it.
Like so:
function classLoader( $class ) {
$paths = explode( PATH_SEPARATOR, get_include_path() );
$file = SITE_PATH . 'classes' . DS . $class . '.Class.php';
if ( file_exists( $file) == false )
{
$exists = false;
foreach ( $paths as $path )
{
$tmp = $path . DS . 'library' . DS . 'classes' . DS . $class . '.Class.php';
if ( file_exists ( $tmp ) )
{
$exists = true;
$file = $tmp;
}
}
if ( !$exists ) { return false; }
}
include $file;
}
spl_autoload_register('classLoader');
Did I go the wrong route? Should I have just done the #include business or am I doing it somewhat in the right direction?
One thing that the Habari project autoloader does that's interesting is cache the whole class file list in memory so that it's not doing disk searches for the files every time a class is requested.
Essentially, you declare a static inside your __autoload() that holds an array of all of the class files, indexed by the class that will cause them to load. For example, the code would use Dir or glob() to generate this static array:
$class_files = array(
'user' => '/var/www/htdocs/system/classes/user.class.php',
);
Then you simply include $class_files[$class] to get the correct file. This is nice and speedy because it gets the catalog from the disk all at once, rather than generating the list or searching for a specific filename each time a new class is referenced. (You would be surprised how much of a speed difference it makes.)
If the class name isn't a key in the array, you can throw a custom exception or generate a stub/mock class to return. Also, if you check out the Habari system autoloader, you'll see that Habari implements __static() in classes that are autoloaded, which is like a constructor for static classes.
include_once() is to be avoided, and the # operator is unnecessary if you've checked for the file to include.
I personally go the way using
function autoload($class) {
/* transform class name into filename ... */
include $class;
}
even without the # to ease debugging (errors are shut down/logged in production)
You might also be interested in the related discussion on the PHP developer list: http://marc.info/?t=125787162200003&r=1&w=2
Related
Codeigniter does not find trivial classes:
Unable to load the requested class: Bcrypt
But the same goes for custom made classes defined in files in application/libraries/. I am used that django lists the folders where it searched for a file, but did not find one. Obviously CI must also iterate over some list of folders or files, but is not as polite to display them along with the error.
It seems as if CI has a naming convention to deduce the (set of) filename(s) where it would expect a class to be. How can I programmatically error_log the list of folders or filenames that Codeigniter or PHP tried to track down this class?
EDIT: The lines of code that produce such a loading-error are:
$autoload['libraries'] = array('database','session','mi_file_fetcher');
in application/config/autoload.php and
$this->load->library("bcrypt");
in application/models/User.php
As stated in the comments, I was not asking for a fix, I was asking for a list.
I managed to do so by updating system/core/Loader.php
protected function _ci_load_library_files_tried($class, $subdir, $params, $object_name)
{
$files_tried = array(BASEPATH . 'libraries/' . $subdir . $class . '.php');
foreach ($this->_ci_library_paths as $path) {
if ($path === BASEPATH) {
continue;
}
array_push($files_tried, $path . 'libraries/' . $subdir . $class . '.php');
}
return $files_tried;
}
protected function _ci_load_library($class, $params = NULL, $object_name = NULL)
{
// ...
// If we got this far we were unable to find the requested class.
$files_tried = $this->_ci_load_library_files_tried($class, $subdir, $params, $object_name);
log_message('error', 'Unable to load the requested class: '.$class .
", tried these files:\n" . join("\n", $files_tried));
show_error('Unable to load the requested class: '.$class .
', tried these files:<ul><li>' . join('</li><li>', $files_tried) . '</li></ul>');
}
Would be great if CI actually provided decent debugging information.
The CodeIgniter (CI) documentation does tell you the default locations of libraries, models, helpers, views and many other framework objects. There isn't a section that explicitly lists the folders though. The Loader Class documentation does tell you, but you have to dig for it a bit.
The subtopics on the General Topics section of the docs clearly state the default locations for the various classes the frameworks uses and where to put custom classes.
In most cases following the prescribed file structure and using the loader class, e.g. (Bcrypt.php is in /application/libraries/)
$this->load->library('bcrypt');
works perfectly.
There are cases (none of which seem to be involved in your problem) where CI needs help. Rather than hack or extend CI_Loader an autoloader is useful in these cases.
There are lots of ways to add an autoloader but my preference is to use CI's Hooks feature. Here's how.
In config.php set 'enable_hooks' to TRUE
$config['enable_hooks'] = TRUE;
These lines go in /application/config/hooks.php
$hook['pre_system'][] = array(
'class' => '',
'function' => 'register_autoloader',
'filename' => 'Auto_load.php',
'filepath' => 'hooks'
);
The following is the contents of /application/hooks/Auto_load.php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
function register_autoloader()
{
spl_autoload_register('my_autoloader');
}
/**
* Allows classes that do not start with CI_ and that are
* stored in these subdirectories of `APPPATH`
* (default APPPATH = "application/" and is defined in "index.php")
* libraries,
* models,
* core
* controllers
* to be instantiated when needed.
* #param string $class Class name to check for
* #return void
*/
function my_autoloader($class)
{
if(strpos($class, 'CI_') !== 0)
{
if(file_exists($file = APPPATH.'libraries/'.$class.'.php'))
{
require_once $file;
}
elseif(file_exists($file = APPPATH.'models/'.$class.'.php'))
{
require_once $file;
}
elseif(file_exists($file = APPPATH.'core/'.$class.'.php'))
{
require_once $file;
}
elseif(file_exists($file = APPPATH.'controllers/'.$class.'.php'))
{
require_once $file;
}
}
}
The function log_message($level, $message) could be used in the above if you wanted.
If you are using some other creative folder structure you will have to modify the above to accommodate that layout.
my class naming convention: class.ClassName.php
my class file naming convention: class.classname.php (hence the strtolower).
the class files are located in the include path: /home/content/XX/XXXXXX/html/projects/include/
//autoload.php
<?php
class Autoload {
public static function autoloadClasses($className) {
$className = strtolower($className);
$file = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'include/class.' . $className. '.php';
require_once($file);
}
}
$register = spl_autoload_register('Autoload::autoloadClasses');
?>
//check4.php
<?php
$company = $s->company;
$projectName = 'development';
$items = array('type', 'scope', 'table', 'conditions');
$things = array('select', '*', 'todos', array('company'=>$company, PROJECT_NAME=>$projectName));
$combinedArray = array_combine($items, $things);
$q = new Query($combinedArray);
?>
verified classes exist and are included http://technicheian.com/images/includedClasses.png
on every page that makes use of a class (e.g. this one calling Query; located class.query.php:
05-Nov-2011 20:18:30]PHP Fatal error: Class 'Query' not found in /home/content/XX/XXXXXX/html/projects/check4.php on line 9
at the end of class.session.php is $s = new Session (noted here to say that the $company variable should not be empty).
I've read pretty much every article, how-to, etc. I can find. What am I missing?
running php 5.2
delete the file_exists check and look at your error logs. You will see which file you were trying to require. I think it may be confusion on what __FILE__ does (because it is working on the autoload.php file).
Edit: It looks like this
dirname(__FILE__) . DIRECTORY_SEPARATOR . 'include/class.'
should be changed to
/home/content/XX/XXXXXX/html/projects/include/class.
There are a number of things for you to check to ensure that autoloading works:
For your custom autoloading to be active it must be registered. So the spl_autoload_register('Autoload::autoloadClasses') must be executed. A good way of doing this is to edit php.ini and set the auto_prepend file to call your autoload file.
Your autoload code must then find the correct file with the correct extension (possibly respecting the php include_path priority that you want).
I need to create a simple file overloading system like symfony does with php files and templates. I will give an example to explain what I need:
Given this folder structure:
- root_folder
- modules
-module1
-file1.php
-file2.php
-file3.php
- specific_modules
-module1
-file2.php
I would like to find a way that automatically loads a file if it is found inside the specific_modules folder (file2.php) when called, if it is not found, it should load file2.php normally from the modules directory.
I would like to do it unobstrusively for the programmer, but not sure if it's possible!!
Any help or advice is welcome, thanks in advance!
skarvin
If the files contain only objects with the same name, then you can write your own autoloader function and register it with spl_autoload_register(). Perhaps something like
function my_loader($class)
{
// look in specific_modules dir for $class
// if not there, look in modules dir for $class
}
spl_autoload_register('my_loader');
This will allow you to code simply as:
$obj = new Thing();
And if Thing is defined in specific_modules, it will use that one, else the default one.
$normal_dir = 'modules';
$specific_dir = 'specific_modules';
$modules = array('module1' => array('file1.php','file2.php','file3.php'));
foreach($modules as $module => $files)
{
foreach($files as $file)
{
if(!file_exists("$specific_dir/$module/$file"))
{
include("$normal_dir/$module/$file");
}
else
{
include("$specific_dir/$module/$file");
}
}
}
This code will work as simply for you as possible, it makes it easy to add new files to your modules and change the directory names. By "load" I am making the assumption you mean include, but that part is easy enough to change.
Similarly to Alex's answer, you could also define an __autoload function:
function __autoload($class_name) {
if (file_exists(__DIR__ . '/specific_modules/' . $class_name . '.php')) {
require __DIR__ . '/specific_modules/' . $class_name . '.php';
}
elseif (file_exists(__DIR__ . '/modules/' . $class_name . '.php')) {
require __DIR__ . '/modules/' . $class_name . '.php';
}
else {
// Error
}
}
Then if you do $obj = new Thing(); it will try to load Thing.php from those two directories.
This is how I autoload all the classes in my controllers folder,
# auto load controller classes
function __autoload($class_name)
{
$filename = 'class_'.strtolower($class_name).'.php';
$file = AP_SITE.'controllers/'.$filename;
if (file_exists($file) == false)
{
return false;
}
include ($file);
}
But I have classes in models folder as well and I want to autoload them too - what should I do? Should I duplicate the autoload above and just change the path to models/ (but isn't this repetitive??)?
Thanks.
EDIT:
these are my classes file names in the controller folder:
class_controller_base.php
class_factory.php
etc
these are my classes file names in the model folder:
class_model_page.php
class_model_parent.php
etc
this is how I name my controller classes class usually (I use underscores and lowcaps),
class controller_base
{
...
}
class controller_factory
{
...
}
this is how I name my model classes class usually (I use underscores and lowcaps),
class model_page
{
...
}
class model_parent
{
...
}
I see you are using controller_***** and model_***** as a class naming convention.
I read a fantastic article, which suggests an alternative naming convention using php's namespace.
I love this solution because it doesn't matter where I put my classes. The __autoload will find it no matter where it is in my file structure. It also allows me to call my classes whatever I want. I don't need a class naming convention for my code to work.
You can, for example, set up your folder structure like:
application/
controllers/
Base.php
Factory.php
models/
Page.php
Parent.php
Your classes can be set up like this:
<?php
namespace application\controllers;
class Base {...}
and:
<?php
namespace application\models;
class Page {...}
The autoloader could look like this (or see 'a note on autoloading' at the end):
function __autoload($className) {
$file = $className . '.php';
if(file_exists($file)) {
require_once $file;
}
}
Then... you can call classes in three ways:
$controller = new application\controllers\Base();
$model = new application\models\Page();
or,
<?php
use application\controllers as Controller;
use application\models as Model;
...
$controller = new Controller\Base();
$model = new Model\Page();
or,
<?php
use application\controllers\Base;
use application\models\Page;
...
$controller = new Base();
$model = new Page();
EDIT - a note on autoloading:
My main auto loader looks like this:
// autoload classes based on a 1:1 mapping from namespace to directory structure.
spl_autoload_register(function ($className) {
# Usually I would just concatenate directly to $file variable below
# this is just for easy viewing on Stack Overflow)
$ds = DIRECTORY_SEPARATOR;
$dir = __DIR__;
// replace namespace separator with directory separator (prolly not required)
$className = str_replace('\\', $ds, $className);
// get full name of file containing the required class
$file = "{$dir}{$ds}{$className}.php";
// get file if it is readable
if (is_readable($file)) require_once $file;
});
This autoloader is a direct 1:1 mapping of class name to directory structure; the namespace is the directory path and the class name is the file name. So the class application\controllers\Base() defined above would load the file www/application/controllers/Base.php.
I put the autoloader into a file, bootstrap.php, which is in my root directory. This can either be included directly, or php.ini can be modified to auto_prepend_file so that it is included automatically on every request.
By using spl_autoload_register you can register multiple autoload functions to load the class files any which way you want. Ie, you could put some or all of your classes in one directory, or you could put some or all of your namespaced classes in the one file. Very flexible :)
You should name your classes so the underscore (_) translates to the directory separator (/). A few PHP frameworks do this, such as Zend and Kohana.
So, you name your class Model_Article and place the file in classes/model/article.php and then your autoload does...
function __autoload($class_name)
{
$filename = str_replace('_', DIRECTORY_SEPARATOR, strtolower($class_name)).'.php';
$file = AP_SITE.$filename;
if ( ! file_exists($file))
{
return FALSE;
}
include $file;
}
Also note you can use spl_autoload_register() to make any function an autoloading function. It is also more flexible, allowing you to define multiple autoload type functions.
If there must be multiple autoload functions, spl_autoload_register() allows for this. It effectively creates a queue of autoload functions, and runs through each of them in the order they are defined. By contrast, __autoload() may only be defined once.
Edit
Note : __autoload has been DEPRECATED as of PHP 7.2.0. Relying on this feature is highly discouraged. Please refer to PHP documentation for more details. http://php.net/manual/en/function.autoload.php
I have to mention something about "good" autoload scripts and code structure, so read the following CAREFULLY
Keep in Mind:
Classname === Filename
Only ONE class per file
e.g: Example.php contains
class Example {}
Namespace === Directory structure
e.g: /Path1/Path2/Example.php matches
namespace Path1\Path2;
class Example {}
There SHOULD be a Root-Namespace to avoid collisions
e.g: /Path1/Path2/Example.php with root:
namespace APP\Path1\Path2;
class Example {}
NEVER use manually defined path or directory lists, just point the loader to the top most directory
Keep the loader AS FAST AS POSSIBLE (because including a file is expensive enough)
With this in mind, i produced the following script:
function Loader( $Class ) {
// Cut Root-Namespace
$Class = str_replace( __NAMESPACE__.'\\', '', $Class );
// Correct DIRECTORY_SEPARATOR
$Class = str_replace( array( '\\', '/' ), DIRECTORY_SEPARATOR, __DIR__.DIRECTORY_SEPARATOR.$Class.'.php' );
// Get file real path
if( false === ( $Class = realpath( $Class ) ) ) {
// File not found
return false;
} else {
require_once( $Class );
return true;
}
}
Where to place it..
/Loader.php <-- there goes the loader
/Controller/... <-- put ur stuff here
/Model/... <-- or here, etc
/...
Remeber:
if you use a root namespace, the loader has to be in this namespace too
you may prefix $Class to match your needs (controller_base {} -> class_controller_base.php)
you may change __DIR__ to an absolute path containing your class files (e.g. "/var/www/classes")
if you don't use namespaces, all files has to be in the same directory together with the loader (bad!)
Happy coding ;-)
A little review at other answers:
THIS IS JUST MY PERSONAL OPINION - NO OFFENSE INTENDED!
https://stackoverflow.com/a/5280353/626731
#alex good solution, but don't make you class names pay for bad file structures ;-)
this is job for namespaces
https://stackoverflow.com/a/5280510/626731 #Mark-Eirich it works, but its pretty nasty/ugly/slow/stiff[..] style to do it this way..
https://stackoverflow.com/a/5284095/626731 #tealou for his problem to be solved this is the most clear approach so far :-) ..
https://stackoverflow.com/a/9628060/626731 #br3nt this reflects my point of view, but please(!) .. dont use strtr!! .. which brings me to:
https://stackoverflow.com/a/11866307/626731 #Iscariot .. to you, a little "you-know-bullshit-benchmark:
Time sprintf preg_replace strtr str_replace v1 str_replace v2
08:00:00 AM 1.1334 2.0955 48.1423 1.2109 1.4819
08:40:00 AM 1.0436 2.0326 64.3492 1.7948 2.2337
11:30:00 AM 1.1841 2.5524 62.0114 1.5931 1.9200
02:00:00 PM 0.9783 2.4832 52.6339 1.3966 1.4845
03:00:00 PM 1.0463 2.6164 52.7829 1.1828 1.4981
Average 1.0771 2.3560 55.9839 1.4357 1.7237
Method Times Slower (than sprintf)
preg_replace 2.19
strtr 51.97
str_replace v1 1.33
str_replace v2 1.6
Source: http://www.simplemachines.org/community/index.php?topic=175031.0
Questions?.. (But he is in fact right about full path including)
https://stackoverflow.com/a/12548558/626731 #Sunil-Kartikey
https://stackoverflow.com/a/17286804/626731 #jurrien
NEVER loop in time critical environment! Don't search for files on os! - SLOW
https://stackoverflow.com/a/21221590/626731 #sagits .. much better than Marks ;-)
function autoload($className)
{
//list comma separated directory name
$directory = array('', 'classes/', 'model/', 'controller/');
//list of comma separated file format
$fileFormat = array('%s.php', '%s.class.php');
foreach ($directory as $current_dir)
{
foreach ($fileFormat as $current_format)
{
$path = $current_dir.sprintf($current_format, $className);
if (file_exists($path))
{
include $path;
return ;
}
}
}
}
spl_autoload_register('autoload');
Here is my solution,
/**
* autoload classes
*
*#var $directory_name
*
*#param string $directory_name
*
*#func __construct
*#func autoload
*
*#return string
*/
class autoloader
{
private $directory_name;
public function __construct($directory_name)
{
$this->directory_name = $directory_name;
}
public function autoload($class_name)
{
$file_name = 'class_'.strtolower($class_name).'.php';
$file = AP_SITE.$this->directory_name.'/'.$file_name;
if (file_exists($file) == false)
{
return false;
}
include ($file);
}
}
# nullify any existing autoloads
spl_autoload_register(null, false);
# instantiate the autoloader object
$classes_1 = new autoloader('controllers');
$classes_2 = new autoloader('models');
# register the loader functions
spl_autoload_register(array($classes_1, 'autoload'));
spl_autoload_register(array($classes_2, 'autoload'));
I'm not sure whether it is the best solution or not but it seems to work perfectly...
What do you think??
My version of #Mark Eirich answer:
function myload($class) {
$controllerDir = '/controller/';
$modelDir = '/model/';
if (strpos($class, 'controller') !== false) {
$myclass = $controllerDir . $class . '.php';
} else {
$myclass = $modelDir . $class . '.inc.php';
}
if (!is_file($myclass)) return false;
require_once ($myclass);
}
spl_autoload_register("myload");
In my case only controller class have the keyword in their name, adapt it for your needs.
Simpliest answer I can give you without writing down those complex codes and even without using the namespace (if this confuses you)
Sample Code. Works 100%.
function __autoload($class_name){
$file = ABSPATH . 'app/models/' . $class_name . '.php';
if(file_exists($file)){
include $file;
}else{
$file = ABSPATH . 'app/views/' . $class_name . '.php';
if(file_exists($file)){
include $file;
}else{
$file = ABSPATH . 'app/controllers/' . $class_name . '.php';
include $file;
}
}
I guess the logic is explainable itself. Cheers mate! Hope this helps :)
Here's what I'd do:
function __autoload($class_name) {
$class_name = strtolower($class_name);
$filename = 'class_'.$class_name.'.php';
if (substr($class_name, 0, 5) === 'model') {
$file = AP_SITE.'models/'.$filename;
} else $file = AP_SITE.'controllers/'.$filename;
if (!is_file($file)) return false;
include $file;
}
As long you name your files consistently, like class_controller_*.php and class_model_*.php, this should work fine.
Everyone is is coping and pasting things from code they got off the internet (With the exception of the selected answer). They all use String Replace.
String Replace is 4 times slower than strtr. You should use it instead.
You should also use full paths when including classes with autoloading as it takes less time for the OS to resolve the path.
__autoload() function should not be use because it is not encourged. Use spl_autoload(), spl_autoload_register() instead. __autoload() just can load one class but spl_autoload() can get more than 1 classes. And one thing more, in future __autoload() may deprecated. More stuff can be find on http://www.php.net/manual/en/function.spl-autoload.php
Altough this script doesn't have the name convention and this thread is already a bit old, in case someone is looking of a possible answer, this is what I did:
function __autoload($name) {
$dirs = array_filter(glob("*"), 'is_dir');
foreach($dirs as $cur_dir) {
dir_searcher($cur_dir, $name);
}
}
function dir_searcher($cur_dir, $name) {
if(is_file("$cur_dir/$name.php")) {
require_once "$cur_dir/$name.php";
}
$dirs = array_filter(glob($cur_dir."/*"), 'is_dir');
foreach($dirs as $cdir) {
dir_searcher("$cdir", $name);
}
}
not sure if it is really optimal, but it searches through the folders by reading dir recursively. With a creative str_replace function you can get your name cenvention.
I use this. Basically define your folder structure (MVC etc) as a constant in a serialised array. Then call the array in your autoload class. Works efficiently for me.
You could obviously create the folder array using another function but for MVC you may as well type it in manually.
For this to work you need to call your classes ...... class.classname.php
//in your config file
//define class path and class child folders
define("classPath","classes");
define("class_folder_array", serialize (array ("controller", "model", "view")));
//wherever you have your autoload class
//autoload classes
function __autoload($class_name) {
$class_folder_array = unserialize (class_folder_array);
foreach ($class_folder_array AS $folder){
if(file_exists(classPath."/".$folder.'/class.'.$class_name.'.php')){require_once classPath."/".$folder.'/class.'.$class_name.'.php';break;}
}
}
In PHP can I include a directory of scripts?
i.e. Instead of:
include('classes/Class1.php');
include('classes/Class2.php');
is there something like:
include('classes/*');
Couldn't seem to find a good way of including a collection of about 10 sub-classes for a particular class.
foreach (glob("classes/*.php") as $filename)
{
include $filename;
}
Here is the way I include lots of classes from several folders in PHP 5. This will only work if you have classes though.
/*Directories that contain classes*/
$classesDir = array (
ROOT_DIR.'classes/',
ROOT_DIR.'firephp/',
ROOT_DIR.'includes/'
);
function __autoload($class_name) {
global $classesDir;
foreach ($classesDir as $directory) {
if (file_exists($directory . $class_name . '.php')) {
require_once ($directory . $class_name . '.php');
return;
}
}
}
I realize this is an older post BUT... DON'T INCLUDE YOUR CLASSES... instead use __autoload
function __autoload($class_name) {
require_once('classes/'.$class_name.'.class.php');
}
$user = new User();
Then whenever you call a new class that hasn't been included yet php will auto fire __autoload and include it for you
this is just a modification of Karsten's code
function include_all_php($folder){
foreach (glob("{$folder}/*.php") as $filename)
{
include $filename;
}
}
include_all_php("my_classes");
How to do this in 2017:
spl_autoload_register( function ($class_name) {
$CLASSES_DIR = __DIR__ . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR; // or whatever your directory is
$file = $CLASSES_DIR . $class_name . '.php';
if( file_exists( $file ) ) include $file; // only include if file exists, otherwise we might enter some conflicts with other pieces of code which are also using the spl_autoload_register function
} );
Recommended by PHP documentation here: Autoloading classes
You can use set_include_path:
set_include_path('classes/');
http://php.net/manual/en/function.set-include-path.php
If there are NO dependencies between files... here is a recursive function to include_once ALL php files in ALL subdirs:
$paths = [];
function include_recursive( $path, $debug=false){
foreach( glob( "$path/*") as $filename){
if( strpos( $filename, '.php') !== FALSE){
# php files:
include_once $filename;
if( $debug) echo "<!-- included: $filename -->\n";
} elseif( is_dir($filename)) { # dirs
$paths[] = $filename;
}
}
# Time to process the dirs:
for( $i=count($paths)-1; $i>=0; $i--){
$path = $paths[$i];
unset( $paths[$i]);
include_recursive( $path, $debug);
}
}
include_recursive( "tree_to_include");
# or... to view debug in page source:
include_recursive( "tree_to_include", 'debug');
<?php
//Loading all php files into of functions/ folder
$folder = "./functions/";
$files = glob($folder."*.php"); // return array files
foreach($files as $phpFile){
require_once("$phpFile");
}
If you want include all in a directory AND its subdirectories:
$dir = "classes/";
$dh = opendir($dir);
$dir_list = array($dir);
while (false !== ($filename = readdir($dh))) {
if($filename!="."&&$filename!=".."&&is_dir($dir.$filename))
array_push($dir_list, $dir.$filename."/");
}
foreach ($dir_list as $dir) {
foreach (glob($dir."*.php") as $filename)
require_once $filename;
}
Don't forget that it will use alphabetic order to include your files.
If your looking to include a bunch of classes without having to define each class at once you can use:
$directories = array(
'system/',
'system/db/',
'system/common/'
);
foreach ($directories as $directory) {
foreach(glob($directory . "*.php") as $class) {
include_once $class;
}
}
This way you can just define the class on the php file containing the class and not a whole list of $thisclass = new thisclass();
As for how well it handles all the files? I'm not sure there might be a slight speed decrease with this.
I suggest you use a readdir() function and then loop and include the files (see the 1st example on that page).
Try using a library for that purpose.
That is a simple implementation for the same idea I have build.
It include the specified directory and subdirectories files.
IncludeAll
Install it via terminal [cmd]
composer install php_modules/include-all
Or set it as a dependency in the package.json file
{
"require": {
"php_modules/include-all": "^1.0.5"
}
}
Using
$includeAll = requires ('include-all');
$includeAll->includeAll ('./path/to/directory');
This is a late answer which refers to PHP > 7.2 up to PHP 8.
The OP does not ask about classes in the title, but from his wording we can read that he wants to include classes. (btw. this method also works with namespaces).
By using require_once you kill three mosquitoes with one towel.
first, you get a meaningful punch in the form of an error message in your logfile if the file doesn't exist. which is very useful when debugging.( include would just generate a warning that might not be that detailed)
you include only files that contain classes
you avoid loading a class twice
spl_autoload_register( function ($class_name) {
require_once '/var/www/homepage/classes/' . $class_name . '.class.php';
} );
this will work with classes
new class_name;
or namespaces. e.g. ...
use homepage\classes\class_name;
Answer ported over from another question. Includes additional info on the limits of using a helper function, along with a helper function for loading all variables in included files.
There is no native "include all from folder" in PHP. However, it's not very complicated to accomplish. You can glob the path for .php files and include the files in a loop:
foreach (glob("test/*.php") as $file) {
include_once $file;
}
In this answer, I'm using include_once for including the files. Please feel free to change that to include, require or require_once as necessary.
You can turn this into a simple helper function:
function import_folder(string $dirname) {
foreach (glob("{$dirname}/*.php") as $file) {
include_once $file;
}
}
If your files define classes, functions, constants etc. that are scope-independent, this will work as expected. However, if your file has variables, you have to "collect" them with get_defined_vars() and return them from the function. Otherwise, they'd be "lost" into the function scope, instead of being imported into the original scope.
If you need to import variables from files included within a function, you can:
function load_vars(string $path): array {
include_once $path;
unset($path);
return get_defined_vars();
}
This function, which you can combine with the import_folder, will return an array with all variables defined in the included file. If you want to load variables from multiple files, you can:
function import_folder_vars(string $dirname): array {
$vars = [];
foreach (glob("{$dirname}/*.php") as $file) {
// If you want to combine them into one array:
$vars = array_merge($vars, load_vars($file));
// If you want to group them by file:
// $vars[$file] = load_vars($file);
}
return $vars;
}
The above would, depending on your preference (comment/uncomment as necessary), return all variables defined in included files as a single array, or grouped by the files they were defined in.
On a final note: If all you need to do is load classes, it's a good idea to instead have them autoloaded on demand using spl_autoload_register. Using an autoloader assumes that you have structured your filesystem and named your classes and namespaces consistently.
Do no write a function() to include files in a directory. You may lose the variable scopes, and may have to use "global". Just loop on the files.
Also, you may run into difficulties when an included file has a class name that will extend to the other class defined in the other file - which is not yet included. So, be careful.