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).
Related
Without using include_once or any include/require how can I reference functions declared in other php files in the current directory? Just like we use fopen.
Including contents of php files which contain code not in functions can be a clutter. It'd be better if function usage is linked automatically to its definition.
I've also checked How to include() all PHP files from a directory? which requires some code to do it.
I'm not able to find answer of this anywhere in internet may be because of too common search terms for this problem.
The most logical approach would be to use OOP and autoloading.
That way you would only load the classes that you actually use.
Otherwise the accepted answer from the question you linked to, is the way to go.
You can use glob to traverse the directory and then include them:
$phpfiles = glob('mydir/*.php');
foreach($phpfiles as $file)
do_something_with_the_file($file) // why not include_once $file ?
As you are referencing functions in other files, you cannot use the autoloader because the autoloader operates on classes. Autoloading classes would be a much better solution.
If you're keen on using classes and OO vs Procedural, this will include a file by the same name as the class that's being called, and will not include class files in the directory that are not needed.
Called from the root directory of the site/application.
define( "APP_PATH", dirname( __FILE__ ) ."/" );
function my_autoloader($class)
{
include 'core/classes/' . $class . '.class.php';
}
spl_autoload_register('my_autoloader');
Assuming you keep all your classes in a similar directory structure:
site/core/classes
You get the idea.
I was wondering when you need to use module_load_include() or require_once to include files which are located within your module.
The key thing that the Drupal module_load_include() function does over and above the standard PHP require_once is that it references the module's path when locating the file, using drupal_get_path().
If you were to use require_once, you would have to do this bit yourself.
The other thing it does is check that the file exists prior to trying to include it, which is handy for avoiding fatal crashes, but rather pointless if you're going to get one anyway when you try to call the functions you tried to include. This is handy though for allowing you to produce more meaningful errors.
At the end of the day, module_load_include() is really just a little utility function provided by Drupal to make things slightly easier for themselves. If you know where the file is located, and you know it exists there, there's very little need to use the Drupal function; you may just as well use require_once.
module_load_include requires Drupal to be loaded fully (Fully Bootstrapped).
syntax: module_load_include($type, $module, $name = NULL);
Eg: module_load_include('inc','module_name','file_name');
if u want to use this function in a global context then use require_once
require_once doesn't need it.
Eg: require_once DRUPAL_ROOT . '/path/file' .
I'm a c# developer, so I'm used to simply compiling a library and including it within a project for use. I haven't really figured out the best way to load different objects within a PHP application. I don't want to keep using require. What is a good approach to take?
If you're using PHP 5.x, you probably want autoloading.
You don't need to keep using require. You can require_once() which will only parse the file if it has not already been loaded.
Also in PHP, since the includes happen at runtime you are free to require_once() in the middle of a conditional if it is appropriate.
// Only load Class.php if we really need it.
if ($somecondition) {
// we'll be needing Class.php
require_once("Class.php");
$c = new Class();
}
else // we absolutely won't need Class.php
I was C# developer in the past and I can tell you that you need to think bit different if you want to write PHP sites. You need to keep in mind that every unnecessary include will increase extra expenses of resources, and your script will work slower. So think twice before add unnecessary includes.
Back to your question you can use include, require, autoload or even phar. Probably PHAR is more close to C# libraries, you can include one PHAR libraries with a number of classes.
Put this in your config file( or any file included in all pages )
function __autoload($class_name) {
require_once "Classes" . $class_name . '.php';
}
Put every class in seperate file with its name.
replace "Classes" with your classes folder.
You can autoload classes. See:
http://us3.php.net/autoload
From that page:
<?php
function __autoload($class_name) {
include $class_name . '.php';
}
$obj = new MyClass1();
$obj2 = new MyClass2();
?>
Note that you can use spl_autoload_register() if you don't want to use the single magic __autoload function.
The autoloader will solve all your problems.
Autoloader, as others mentioned.
If you want to go step further... look at the way how Kohana (for example) solved the problem.
This question is the first Stack Overflow result from searching "php how to load classes" and other answers which provide examples for autoloading suggest the use of __autoload(). Please note that use of __autoload() is deprecated as of PHP 7.2 and its use is discouraged. Using spl_autoload_register is suggested instead.
The example snippet below is from the documentation page:
spl_autoload_register(function ($class_name) {
include 'classes/' . $class_name . '.php';
});
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 always struggled with how to best include classes into my php code. Pathing is usually an issue but a few minutes ago i found this question which dramatically helps that. Now I'm reading about __autoload and thinking that it could make the process of developing my applications much easier. The problem is i like to maintain folder structure to separate areas of functionality as opposed to throwing everything into a general /lib folder. So if i override autoload to do a deep search of a class folder including all subfolders, what performance hits can i expect?
Obviously this will depend on scale, depth of the folder structure and number of classes but generally I'm asking on a medium scale project will it cause problems.
__autoload is great, but the cost of stating all the files in a recursive search function is expensive. You might want to look at building a tree of files to use for autoloading. In my framework, I consistently name files for their classes and use a map that is cached for the data.
Check out http://trac.framewerk.org/cgi-bin/trac.fcgi/browser/trunk/index.php [dead link] starting at line 68 for an idea of how this can be done.
Edit: And to more directly answer your question, without caching, you can expect a performance hit on a site with medium to heavy traffic.
A common pattern (Pear, Zend Framework as examples...) is to make the classname reflect the path, so Db_Adapter_Mysql will be in at /Db/Adapter/Mysql.php, from somewhere that's added to the include-path.
There are 2 ways that you could easily do this, first of all, name your classes so that they'll define the structure of where to find them
function __autoload($classname)
{
try
{
if (class_exists($classname, false) OR interface_exists($classname, false))
{
return;
}
$class = split('_', strtolower(strval($classname)));
if (array_shift($class) != 'majyk')
{
throw new Exception('Autoloader tried to load a class that does not belong to us ( ' . $classname . ' )');
}
switch (count($class))
{
case 1: // Core Class - matches Majyk_Foo - include /core/class_foo.php
$file = MAJYK_DIR . 'core/class_' . $class[0] . '.php';
break;
case 2: // Subclass - matches Majyk_Foo_Bar - includes /foo/class_bar.php
$file = MAJYK_DIR . $class[0] . '/class_' . $class[1] . '.php';
break;
default:
throw new Exception('Unknown Class Name ( ' . $classname .' )');
return false;
}
if (file_exists($file))
{
require_once($file);
if (!class_exists($classname, false) AND !interface_exists($classname, false))
{
throw new Exception('Class cannot be found ( ' . $classname . ' )');
}
}
else
{
throw new Exception('Class File Cannot be found ( ' . str_replace(MAJYK_DIR, '', $file) . ' )');
}
}
catch (Exception $e)
{
// spl_autoload($classname);
echo $e->getMessage();
}
}
Or, 2, use multiple autoloaders. PHP >=5.1.2 Has the SPL library, which allows you to add multiple autoloaders. You add one for each path, and it'll find it on it's way through. Or just add them to the include path and use the default spl_autoload()
An example
function autoload_foo($classname)
{
require_once('foo/' . $classname . '.php');
}
function autoload_bar($classname)
{
require_once('bar/' . $classname . '.php');
}
spl_autoload_register('autoload_foo');
spl_autoload_register('autoload_bar');
spl_autoload_register('spl_autoload'); // Default SPL Autoloader
Autoload is great PHP feature that helps you very much...
The perfomance wouldn't suffer if will use the smart taxonomy like:
1. every library stays in the folders "packages"
2. every class is located by replacing the "_" in the class name with the "/" and adding a ".php" at the end
class = My_App_Smart_Object
file = packages/My/App/Smart/Object.php
The benefits of this approach(used by almost any framework) is also a smarter organization of your code :-)
Hunting for files all over the place will make things slower (many more disk hits). Loading all of your classes in case you might need them will make things take more memory. Specifying which classes you need in every file is difficult to maintain (i.e. they don't get removed if they're no longer used).
The real question is which of these is more important to you? They're all tradeoffs, in the end, so you have to pick one. It's arguable, though, that most of the overhead in the second and third options has to do with actually compiling the code. Using something like APC can significantly reduce the overhead of loading and compiling every class on every page load.
Given the use of APC, I would likely take the approach of dividing up my code into modules (e.g. the web interface module, the database interaction module, etc.) and have each of those modules import all the classes for their module, plus classes from other modules they may need. It's a tradeoff between the last two, and I've found it works well enough for my needs.
I tend to use a simple approach where __autoload() consults a hash mapping class names to relative paths, which is contained in a file that's regenerated using a simple script which itself performs the recursive search.
This requires that the script be run when adding a new class file or restructuring the code base, but it also avoids "cleverness" in __autoload() which can lead to unnecessary stat() calls, and it has the advantage that I can easily move files around within my code base, knowing that all I need to do is run a single script to update the autoloader.
The script itself recursively inspects my includes/ directory, and assumes that any PHP file not named in a short list of exclusions (the autoloader itself, plus some other standard files I tend to have) contains a class of the same name.
Zend Framework's approach is to do autoload based on the PEAR folder standard (Class_Foo maps to /Class/Foo.php), however rather than using a set base path it uses the include_path.
The problem with their approach is there's no way to check beforehand if a file exists so the autoload will try to include a file that doesn't exist in any of the include_path's, error out, and never give any other autoload functions registered with spl_autoload_register a chance to include the file.
So a slight deviation is to manually provide an array of base paths where the autoload can expect to find classes setup in the PEAR fashion and just loop over the base paths:
<?php
//...
foreach( $paths as $path )
{
if( file_exists($path . $classNameToFilePath) )
include $path . $classNameToFilePath;
}
//...
?>
Granted you'll kinda be search but for each autoload you'll only be doing at worst n searches, where n is the number of base paths you are checking.
But if you find yourself still having to recursively scan directories the question is not "Will autoload hurt my performance," the question should be "why am I tossing my class files around in a random structure?" Sticking to the PEAR structure will save you so many headaches, and even if you decide to go with manually doing your includes as opposed to autoload, there will be no guessing as to where the class files are located when you do your include statements.