avoid redeclaring an interface for more one time - php

I have an interface which I named Manager, and two classes UtilisateurManager and StageManager, and the both of them implements the Manager interface.
In each class I included the interface Manager as the following :
require '../helpers/Manager.class.php';
Then I needed to use these two classes at once in a php script, but I got the error that I can't redeclare class Manager.
I tried to work with the function class_exists() but it's not useful in my case.
How can I solve this problem ?

Maybe you can use require_once instead of require.
require_once '../helpers/Manager.class.php';

You need to implement a simple autoloader which will try to load class/interface only if it isn't already loaded, and forget about direct require/include then. It is considered good practice to leave the filesystem details out of the class file: you may reuse it in other project where your directories system might change, so you'll need to edit the class again.
A simple example:
class Autoloader
{
protected $directories = array();
public function register()
{
// register 'loadClass' method as an autoloader
spl_autoload_register(array($this, 'loadClass'));
}
public function addSource($dir)
{
$this->directories[] = $dir;
}
public function loadClass($className)
{
foreach ($this->directories as $dir) { // search in every registered sources root
$fileName = $dir.DIRECTORY_SEPARATOR.$className.'.class.php';
if (file_exists($fileName) {
include($fileName);
return; // halt when file was found
}
}
}
}
// bootstrap file
$autoloader = new Autoloader;
$autoloader->register();
(spl_autoload_register documentation)
Please note that this realization will cycle through the folders, and this is certainly not the desired solution. The best option today is to build project according to PSR-4 spec - autoloader implementation will have to check existence of a single file only. It may be a little hard to dive into namespaces without any preparation, but once you get familiar with this coding style, you will forget about direct file load.
The last thing, i want to warn you about your naming convention - your Interface is stored in a .class.php file, and this is confusing.

Related

Autoloaders in PHP - two running at a time

I understand how to register autoloaders and even how to create one, that's no issue at all. How ever the main issue is - how do you have two auto loaders running side by side for something like:
class project_one_folder_class extends project_two_folder_class{}
You'll notice that the child class belongs to a project which is reaching out and calling the parent class which is locate in a different project.
The way the projects are linked project two's classes are always seen by the auto loader, how ever project one's classes are never seen.
So the way I thought around this was to write two auto loaders and register them because php will look in on then the other. How ever php seems to be looking in only one and not the other.
how would you solve this?
Edit
Project two is parent, Project one is child. This is more expanded question then What was posted on this question.
To better expand this is my class.
class AisisCore_Loader_AutoLoader{
protected static $_instance;
public function get_instance(){
if(null == self::$_instance){
self::$_instance = new self();
}
return self::$_instance;
}
public function reset_instance(){
self::$_instance = null;
}
public function register_auto_loader(){
spl_autoload_register(array($this, 'load_class'));
spl_autoload_register(array($this, 'load_child_class'));
}
public function load_class($class){
$path = str_replace('_', '/', $class);
if(file_exists(get_template_directory() . '/' . $path . '.php')){
require_once(get_template_directory() . '/' . $path . '.php');
}
}
public function load_child_class($class){
$path = str_replace('_', '/', $class);
if(file_exists(get_stylesheet_directory() . '/' . $path . '.php')){
require_once(get_stylesheet_directory() . '/' . $path . '.php');
}
}
}
Currently this class will load anything in the parent project. It will even load parent project objects in the child project. How ever no child object can be loaded using this class as it is not found.
Those familiar with WordPress will instantly say, yes its because you have get_template_directory when you want get_stylesheet_directory How ever - Knowing this - I want to write then two auto loaders, one that will load child projects objects using get_stylesheet_directory and then one that will load parent objects via get_stylesheet_directory so that:
class project_one_folder_class extends project_two_folder_class{}
works and loads, with out error.
This is a little rough, but you actually only need one autoloader that just checks within multiple directories:
abstract class Hakre_Theme_AutoLoader
{
public static $directories;
public static function init()
{
// configure paths
self::$directories = array(
get_template_directory(), // current theme, parent in case of childtheme
get_stylesheet_directory(), // current theme, child in case of childtheme
);
// please double check if you really need to prepend
return spl_autoload_register('Hakre_Theme_AutoLoader::autoload', true, true);
}
public static function autoload($class)
{
$filename = str_replace('_', '/', $class) . '.php';
foreach (self::$directories as $directory) {
$path = $directory . '/' . $filename;
if (is_file($path)) {
require($path);
return; # leave because the class has been loaded
}
}
}
}
Hakre_Theme_AutoLoader::init();
## If you're unsure all worked out properly:
var_dump(Hakre_Theme_AutoLoader::$directories);
This should actually do it, however I've not tested it. See the var_dump, you can debug if the correct directories are registered or not. No need to have multiple callbacks only because you want to check in two directories.
Well, of course you could just look up a second path when the first file_exists returns false - in the very same autoloader.
You can also register a second autoloader for the second path.
PHP docs addresses this:
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.
Separate the autoloading process!
PHP is working like this: At some point, the code execution stumbles upon a class reference that is not yet loaded. $obj = new project_one_folder_class()
Now the registered autoloader functions are called, starting with the one added first (unless the ones added later are using the "prepend" parameter).
The first (and all subsequent) autoload function gets the name of the class that should be loaded. The function now has the task to decide
Is it it's task to load this class? If not, do nothing, let the other functions try to load it.
If this function is responsible to load the class, try to make up a path and filename out of the known class name, and require this file.
Step 1 is usually solved by looking if the class name to be loaded starts with a certain prefix. In your case, the autoloader responsible for loading classes starting with "project_one_" should NOT try to load any other classes starting with something else.
Step 2 takes place if the autoloader knows that it must perform the autoloading. It now transforms the class name into a relative path and filename, adds the base directory, and then requires the file.
Requiring a file that defines a class which extends another class (or implements interfaces) can then trigger another run of autoloading with any still unknown classes. In your case, the autoload process is started again with the class name "project_two_folder_class". Note that the first autoloader for "project_one_" classes will be called again with this second class name, but it must not do anything, because it does not know how to load these classes. This is up to the autoloader that knows about "project_two_" classes.
Order of registration should not matter for the different autoloaders. If it does, autoloaders misbehave.
Because it is a common pattern to simply transform any underscore characters in class names into DIRECTORY_SEPARATOR, as well as the backslashes from namespaces, add ".php" at the end, and then try to load this file from a defined base directory, the code for two of these autoloaders will be identical, and the problem is reduced to configuring only one autoload function with these two cases: Which prefix should be present, and in which base directory should the file be expected to be, provided that the class name can be transformed into a relative path to the file.
Checking in every case whether the file exists in a certain directory or not is not optimal for performance. You'll end up doing plenty of checks for files that you will be able to know you cannot load by simply looking at the class name.
And by the way: Autoloader functions do not need to be singletons. In fact, your singleton implementation is broken, and useless. Instantiate the autoloader with new, maybe pass some configuration values into the constructor, and call spl_autoload_register(), and you should be done.
You can add more than one loader, just register each function with spl_autoload_register().
procedural style:
spl_autoload_register('loader_function1'));
// your second class location
spl_autoload_register('loader_function2'));
or in a OO style
spl_autoload_register(array($this, 'loader_function1'));
spl_autoload_register(array($this, 'loader_function2'));
However based on your question: you probably can accomplish the same thing by having a more flexible autoloader
see my answer in a different question here:
Class autoloader in wordpress plugin

How can I reconcile SplClassLoader's namespace requirement with my custom directory layout?

I recently starting writing a custom MVC framework in PHP. It's basically a learning exercise.
My classes are located in the following directories:
system/libraries/
system/controllers/
system/models
application/libraries/
application/controlers/
application/models
I'm not using namespaces because I can't figure out how to instantiate controllers using namespaces and Apache 2 handler style URLs (controller/action/id). I created a Bootstrap class to autoload my other classes:
class Bootstrap
{
public function autoloadClasses($class)<br/>
{
$class .= '.php';
$classDirectories = array(
SYSTEM_LIBS_DIR,
SYSTEM_CONTROLLERS_DIR,
SYSTEM_MODELS_DIR,
APPLICATION_LIBS_DIR,
APPLICATION_CONTROLLERS_DIR,
APPLICATION_MODELS_DIR
);
foreach ($classDirectories as $classDirectory) {
$directoryIterator = new DirectoryIterator($classDirectory);
foreach($directoryIterator as $file) {
if ($file == $class) {
include $classDirectory . $class;
break 2;
}
}
}
}
public function register()
{
spl_autoload_register(array($this, 'autoloadClasses'), true);
}
public function init()
{
$this->register();
$loader = new Loader($_GET);
$controller = $loader->createController();
$controller->executeAction();
}
}
It works fine. However, I know I should really be using the implementation recommended by PSR-0:
https://gist.github.com/221634
However, I can't figure out how to get it to work without namespaces. It looks like the namespace is an optional pararmeter. However, if I do the following, nothing happens -- not even an error in the Apache logs:
$libLoader = new SplClassLoader('', 'system/libraries');
The goal of PSR-0 was to try and specify how external third-party library classes should be named, and where the files containing those classes should live on disk. This goal was accomplished, and from a high level, it's not too bad of a thing. Interopability and not stepping all over other libraries is a good thing.
Your directory layout and class naming scheme doesn't mesh with PSR-0, which means SplClassLoader is going to be nigh-useless for you.
You have two options:
Rename all of your classes, shuffle them into a namespace hierarchy, and refactor the rest of the code that needs to worry about it, or
Don't use SplClassLoader and write your own autoloader.
If you're building a library intended for external distribution, it'll be a good idea to make yourself PSR-0 compliant, as it's pretty darn simple, logical and painless.
If you're building your own app for your own use and don't intend it as a library, then you are under no requirement to do all of that work, and you shouldn't, because it'd be silly. This looks like it's the case, so I can end with a big fat: don't bother.
I got it to work. YAY!
Here is the code from my front controller (index.php) I'm going to refactor it since it would be cleaner to simply make one call to some type of bootstrap class:
<?php
use NeilMVC\system\libraries\Loader;
require_once('conf/conf.php');
require_once('SplClassLoader.php');
$loadSystemLibraries = new SplClassLoader('NeilMVC\system\libraries');
$loadSystemControllers = new SplClassLoader('NeilMVC\system\controllers');
$loadSystemModels = new SplClassLoader('NeilMVC\system\models');
$loadApplicationLibraries = new SplClassLoader('NeilMVC\application\libraries');
$loadApplicationControllers = new SplClassLoader('NeilMVC\application\controllers');
$loadApplicationModels = new SplClassLoader('NeilMVC\application\models');
$loadSystemLibraries->register();
$loadSystemControllers->register();
$loadSystemModels->register();
$loadApplicationLibraries->register();
$loadApplicationControllers->register();
$loadApplicationModels->register();
$loader = new Loader($_GET);
$controller = $loader->createController();
$controller->executeAction();
I had to refactor some of the classes in order to resolve fully qualified classes to unqualified names used in the MVC-style URLs. It wasn't that hard to do, I just had to tinker with it to understand it. If anyone want to know more, you can email me through my website http://neilgirardi.com
Cheers and happy holidays!

multiple spl_autoload_register

what is/are the benefit(s) of having multiple spl_autoload_register
example:
spl_autoload_register('autoload_systems');
spl_autoload_register('autoload_thirdparties');
spl_autoload_register('autoload_services');
vs:
using one
spl_autoload_register('autoload'); or __autoload();
and then do the logic inside the function.
eg:
$ftp = new systems_ftp();
$services = new services_cron_email();
If you have one __autoload() and you include a third party library which also had one, it would be clobbered.
Registering multiple autoloads with spl_autoload_register() ensures you can have your code dropped in with existing code (think libraries, etc) without clobbering or shadowing of existing/future autoloads.
In addition, the PHP manual states...
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.
I guess no need to add multiple but it's on your logic.
The way spl_autoload_register works is awesome.
Suppose one have 3rd parties directories and that is usually manages through namespace which also represents their path.
Consider this simple class as autoloader class
class MyAutoLoader {
public function __construct()
{
spl_autoload_register( array($this, 'load') );
}
function load( $class )
{
$filepath = 'classes/'.$class.'.php';
require_once( $filepath);
}
}
Then in index file include this loader file and create instance of this class:
$autoload = new MyAutoLoader();
Now you can directly create the instances of classes.
Suppose we have 'Person' class in directory classes\QMS\SERVICES\Person.php and same path is the namespace of that class
$person = new QMS\SERVICES\Person();
Now when when you will use new it will check if this class exists and value as a string will be passes to 'load' function of class 'MyAutoLoader'. and there it will get included. Or you can change the function 'load' to fix the path of your class files put your if conditions or whatever need to b done to fix the paths.

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.

Efficient PHP auto-loading and naming strategies

Like most web developers these days, I'm thoroughly enjoying the benefits of solid MVC architecture for web apps and sites. When doing MVC with PHP, autoloading obviously comes in extremely handy.
I've become a fan of spl_autoload_register over simply defining a single __autoload() function, as this is obviously more flexible if you are incorporating different base modules that each use their own autoloading. However, I've never felt great about the loading functions that I write. They involve a lot of string checking and directory scanning in order to look for possible classes to load.
For example, let's say I have an app that has a base path defined as PATH_APP, and a simple structure with directories named models, views and controllers. I often employ a naming structure whereby files are named IndexView.php and IndexController.php inside the appropriate directory, and models generally have no particular scheme by default. I might have a loader function for this structure like this that gets registered with spl_autoload_register:
public function MVCLoader($class)
{
if (file_exists(PATH_APP.'/models/'.$class.'.php')) {
require_once(PATH_APP.'/models/'.$class.'.php');
return true;
}
else if (strpos($class,'View') !== false) {
if (file_exists(PATH_APP.'/views/'.$class.'.php')) {
require_once(PATH_APP.'/views/'.$class.'.php');
return true;
}
}
else if (strpos($class,'Controller') !== false) {
if (file_exists(PATH_APP.'/controllers/'.$class.'.php')) {
require_once(PATH_APP.'/controllers/'.$class.'.php');
return true;
}
}
return false;
}
If it's not found after that, I might have another function to scan sub-directories in the models directory. However, all the if/else-ing, string checking and directory scanning seems inefficient to me, and I'd like to improve it.
I'm very curious what file naming and autoloading strategies other developers might employ. I'm looking specifically for good techniques to employ for efficient autoloading, and not alternatives to autoloading.
This is what I have been using in all of my projects (lifted straight from the source of the last one):
public static function loadClass($class)
{
$files = array(
$class . '.php',
str_replace('_', '/', $class) . '.php',
);
foreach (explode(PATH_SEPARATOR, ini_get('include_path')) as $base_path)
{
foreach ($files as $file)
{
$path = "$base_path/$file";
if (file_exists($path) && is_readable($path))
{
include_once $path;
return;
}
}
}
}
If I look for SomeClass_SeperatedWith_Underscores it will look for SomeClass_SeperatedWith_Underscores.php followed by SomeClass/SeperatedWith/Underscores.php rooted at each directory in the current include path.
EDIT: I just wanted to put out there that I use this for efficiency in development, and not necessarily processing time. If you have PEAR on your path then with this you can just use the classes and don't have to include them when you need them.
I tend to keep my classes in a hierarchy of directories, with underscores breaking up namespaces... This code lets me keep the file structure nice and tidy if I want, or to inject a quick class file without nested directories if I want (for adding a single class or two to a library that it is defendant on, but not part of the project I am currently working on.)
I landed on this solution:
I created a single script that traverses my class library folder (which contains subfolders for separate modules / systems), and parses the file contents looking for class definitions. If it finds a class definition in a php file (pretty simple regex pattern), it creates a symlink:
class_name.php -> actual/source/file.php
This lets me use a single, simple autoload function that needs only the class name and the path to the main symlink folder, and doesn't have to do any path/string manipulation.
The best part is that I can rearrange my source code completely or add a new subsystem and just run the link generating script to have everything autoloaded.
If you want efficiency then you shouldn't be using the autoload feature at all. The autoload feature is for being lazy. You should be providing an explicit path to your include files when you include them. If your autoload function can find these files then you could code to find them explicitly. When you are working on the view part of the code and about to load a new view class, by letting the autoload function handle it, it first assumes your class is a model class? That's inefficient. Instead your code should just be:
include_once $this->views_path . $class . '.php';
If you need multiple "view" paths, make a function that loads views:
public function load_view($class) {
// perhaps there's a mapping here instead....
foreach ($this->views_paths as $path) {
$filename = $path . $class . '.php';
if (file_exists($filename)) {
include_once $filename;
}
}
throw ....
}
In any case, at the point where the include occurs, you have the greatest/most accurate information about the class you want to load. Using that information to load the class fully is the only efficient class loading strategy. Yes, you may end up with more class variables or (heaven forbid) some global variables. But that is a better tradeoff than just being lazy and scanning parts of the file system for your class.

Categories