I am having trouble implementing a particular class in PHP. I want to use Anthony Ferrara's RandomLib library in my Zend Framework application (you can find it here.)
I've been programming in PHP for a few years now, so I know my way around it for the most part. But I have to admit that I'm kind of clueless when it comes to using classes that implement namespaces. Here's what I've got in my code:
public static function generateToken()
{
require_once 'RandomLib/Factory.php';
$factory = new \RandomLib\Factory;
$generator = $factory->getMediumStrengthGenerator();
return $generator->generate(16);
}
Unfortunately, I'm getting the following error:
Fatal error: Class 'SecurityLib\AbstractFactory' not found in C:\xampp\php\includes\RandomLib\Factory.php on line 30
Like I said, I really have no idea what's going on here. I don't know if I'm supposed to use some kind of use statement in my class or not.
With autoloader with ZF 1.*, asuming you put your factoru into application_name/libs/RandomLibFactory.php as RandomLibFactory class it should look like this:
public static function generateToken() {
$factory = $locator = new RandomLibFactory();
$generator = $factory->getMediumStrengthGenerator();
return $generator->generate(16); }
For anyone whom spent lot of time and didn't find a clue, tearing his hairs apart and hitting the wall to death:
you need to have an autoloader as in "bootstrap.php" in the folder "test/", to manage every namespace... or you need to link every file in the folder which is not very smart. See spl_autoload_register in php.net
you just downloaded RandomLib, which depends on another library (the author didn't mentioned it): so you need SecurityLib (it has the same folder structure: copy what is inside "lib/" into the other "lib/" folder.
example of autoloader for a script calling from the root folder "RandomLib-1.1.0/" (see that 'lib' in the $path ?):
spl_autoload_register(function ($class) {
$nslen = strlen(__NAMESPACE__);
if (substr($class, 0, $nslen) != __NAMESPACE__) {
//Only autoload libraries from this package
return;
}
$path = substr(str_replace('\\', '/', $class), $nslen);
$path = __DIR__ . '/lib/' . $path . '.php';
if (file_exists($path)) {
require_once $path;
}
});
now you are set and can use classes freely without worrying about including or requiring files.
$factory = new RandomLib\Factory;
$generator = $factory->getLowStrengthGenerator();
//$generator = $factory->getMediumStrengthGenerator();
//$generator = $factory->getHighStrengthGenerator();
$randomStringLength = 16;
$randomStringAlphabet = '0123456789#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/';
$randomString = '';
for ($i=0;$i<10;$i++){
$randomString = $generator->generateString( $randomStringLength , $randomStringAlphabet);
echo $randomString.'<br>';
}
I too tore out many hairs, before I found the solution for my Windows machine.
I downloaded the Windows version of Composer (which I had barely heard of let alone used).
I used it to install RandomLib (as shown in the Install section of the instructions - use a command box in Windows)
This generated a vendor folder containing a composer folder an ircmaxell folder and an autoload.php file; these I uploaded to a suitable place in my website The vendor directory includes both the random-lib and the - required - security-lib libraries.
In the program in which I wanted to generate random text I included that autoload.php (preceded by suitable directory pointers)
Then I was good to go to create a factory, generator and string as shown in the library's instructions
Related
Recently I decided to upgrade some projects from my own (...) autoloader solution to a Composer PSR-4 autoloader. My code already followed PSR-4 so, no big deal there.
On a specific case, I had the following code:
public static function isAutoLoadable($className)
{
$className = ltrim($className, "\\");
$file = $GLOBALS["Path"] . "/src/" . str_replace("\\", "/", $className) . ".php";
if (false !== stream_resolve_include_path($file))
return $file;
return false;
}
It allowed me to check whatever a given class name could be loaded, without actually trying to load it and result on a PHP Class * not found error.
Use case:
I'm currently using it to replace controllers that by some reason couldn't be found with a generic error one, avoiding an App crash and just telling the user something went wrong... then extra internal logging is done.
A function would be good since I can call it before trying to load a controller... I don't want this behavior to spread to any other classes on the app
So my question is: Is there a equivalent way to check if Composer is able to autoload some class without forcing it to load it and cause an error? -- So I can take further actions in case the class wasn't found?
I am trying to add the Imagine image library into a Codeigniter application, but this is the first time I have ever encounter the "namespace" and "use" concept which I just don't get. Most Libs usually need an include, require etc... to make them work with your framework but I am having a hard time trying to implement this "namespace", "use" approach.
Now how far did I get, well I downloaded the Lib, put the Imagine folder in my libraries folder in CI where I have another image Lib call wideimage which I had no problem adapting to CI. I try to be creative and and loaded the library files just like any regular library file is loaded in CI.
And thats where the problem began, I started getting a lot of errors like class is not found got the error line and right away I thought it may need that other file that has that class now that work for some of the errors that it kept on giving me but its like every time a new lib file is loaded another error comes up and some errors just won't go away even if the file with the main class is present.
Now I did found an article on how to set an SPL auto load and I got the following code
set_include_path('/application/libraries/Imagine' . PATH_SEPARATOR . get_include_path());
function imagineLoader($class) {
$path = $class;
$path = str_replace('\\', DIRECTORY_SEPARATOR, $path) . '.php';
if (file_exists($path)) {
include $path;
}
}
spl_autoload_register('\imagineLoader');
But never got it to work, in this case it gave me an error of CI classes or files where not being found.
Now again to my questions is there a way to implemet this Imagine image library into Codeigniter?
To either load it through the regular library loader or through an autoload file?
Something like this;
class Test extends CI_Controller {
function __construct()
{
parent::__construct();
$this->load->library('imagine');
}
public function index()
{
// Do some cool things with the image lib functions
}
}
Well I would really appreciate anyone's help on this in the mean time I will keep on looking around the web to see if I can find an answer.
Anyway after a day of looking I finally found a way to do it, and thank you simplepie feed parser I knew I had seen similar code in the past.
Anyway I actually looked over at the simplepie autoloader.php file which loads the classes to use simplepie and I just did some small adjustments to the code to be able to use Imagine Lib in Codeigniter.
So here are the steps and code:
1 download the Imagine Library at:
https://github.com/avalanche123/Imagine
2 Copy the Imagine folder into your CI application libraries folder: application/libraries
3 Create a file and call it imagine_autoload.php
4 add the following code to the imagine_autoload.php file
set_include_path('/application/libraries/Imagine' . PATH_SEPARATOR . get_include_path());
function imagineLoader($class) {
$path = $class;
$path = str_replace('\\', DIRECTORY_SEPARATOR, $path) . '.php';
if (strpos($class, 'Imagine') !== 0)
{
return;
}
include_once $path;
}
spl_autoload_register('\imagineLoader');
Now to the fun part on your controller do the following:
require_once('./application/libraries/imagine_autoloader.php');
// Here you can use the imagine imagine tools
use Imagine\Image\Box;
use Imagine\Image\Point;
class Testing extends CI_Controller {
function __construct()
{
parent::__construct();
}
function index($offset = 0)
{
$imagine = new \Imagine\Gd\Imagine();
$image = $imagine->open('/path/to/image.jpg');
$thumbnail = $image->thumbnail(new Imagine\Image\Box(100, 100));
$thumbnail->save('/path/to/thumnail_image.jpg');
}
}
Now go an look at where you saved the new image and you will find a new image that has been re size.
Hopefully someone will find this useful.
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.
I'm actually trying to create a MVC framework for my own, however I'm having troubles with the Autoload. It's not a problem actually, but I'd like to ask the gurus, how are they using the spl_autoload_register function when there are different directories.
Lets say we have the following directories:
Controllers
Libs
Models
Each folder contains different classes, like:
Controllers:
Main.php
File.php
About.php
Libs:
Main.php
Front_controller.php
Models:
Index.php
File.php
Login.php
You can notice that some file names might be found with the same name in different directories. Okay, so this is what I've tried so far:
spl_autoload_register(function ($class) {
$pathContorllers = 'Controllers/' . $class . '.php';
$pathLibs = 'Libs/' . $class . '.php';
$pathModels = 'Models/' . $class . '.php';
if (file_exists($pathContorllers)) {
require_once $pathContorllers;
} elseif (file_exists($pathLibs)) {
require_once $pathLibs;
} elseif (file_exists($pathModels )) {
require_once $pathModels ;
}
});
It is working well, however I'm sure that there is another way to make everything simpler. Can anyone suggest me how can I make this code better or simpler / what are gurus using in this situation?
For the purpose of keeping individuals who may come across this answer from obtaining out-of-date information I have updated it in regards to the latest PSR autoloading standards. The original answer has been maintained for historical purposes and for those who are only interested in the PSR-0 autoloader.
Updated Answer
The PHP-FIG has officially deprecated the PSR-0 standard in favor of the alternative autoloader, PSR-4. Although the two are similar in some aspects they are also very different in others. (E.g.: the handling of underscores in class names.)
You may be thinking to yourself -- "I use PSR-0 now and it works fine." The truth of the matter is that PSR-0 will still work fine for certain projects. This is especially true when backwards compatibility with a package that doesn't use namespaces is concerned. PSR-0 is still a decent autoloading principle, but it has its own shortcomings.
Of course, if there is one thing that is a constant with programming, it is that code eventually changes and programming techniques continue to evolve. You can do yourself a favor today by preparing yourself for tomorrow. Therefore, if you are just starting a project or are trying to port a project to a newer version of PHP that can use namespaces, you should seriously consider using the PSR-4 autoloader.
It is also worth noting that if you are developing a project that does not use namespaces then PSR-4 does not apply to you. In this case PSR-0 or your own custom autoloader applies.
Original Answer
If you want to go with namespaces in your classes, then the PSR-0 route is a pretty good way to autoload. Basically your namespace represents you directory structure and classes can be loaded based on a convention.
If the PSR-0 method doesn't meet all your needs (or doesn't play nice with existing code) you can still add more functions with spl_autoload_register and PHP will go through them one by one in an attempt to load classes.
Example usage:
First thing is first, if you aren't familiar with namespaces in PHP then you will benefit from checking out the PHP manual on the subject. They can be a bit confusing at first, but their benefits are worth the initial confusion.
So I said that PSR-0 works by associating your namespaces with your directory structure. Let's use your directories for an example. You have in your root folder (wherever it may be) the following:
Project directory: <- Let's call this directory "MyProject"
Controllers:
Main.php
File.php
About.php
Libs:
Main.php
Front_controller.php
Models:
Index.php
File.php
Login.php
index.php <- Let's say this is your entry point file, this is where you will be autoloading stuff from.
Now let's take a look at your controller Main.php. Two things to keep in mind is that the class name needs to be the name of the file and the namespace for that class is the directory path to that file. So Main.php should look something like this:
<?php
namespace MyProject\Controllers;
class Main {
//Field vars, contructor, methods, etc. all go here.
}
?>
You would do the same thing for your your Login model
<?php
namespace MyProject\Models;
class Login {
//Field vars, contructor, methods, etc. all go here.
}
?>
Now in your index.php file (out in the root directory - MyProject) you would make your call to the spl_autoload_register and give it the PSR-0 autoloader.
spl_autoload_register( function ($className) {
$className = ltrim($className, '\\');
$fileName = '';
$namespace = '';
if ($lastNsPos = strrpos($className, '\\')) {
$namespace = substr($className, 0, $lastNsPos);
$className = substr($className, $lastNsPos + 1);
$fileName = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
}
$fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
require $fileName;
});
//Now you can make your call to your objects without a bunch of include/require statements
$main = new \MyProject\Controllers\Main(); //Instantiates your 'Main' controller
$login = new \MyProject\Models\Login(); //Instantiates your 'Login' model
Hopefully that helps make better sense of it, and again, if you don't want to use namespaces you can always just keep adding closures into the SPL autoload stack. You can have 10 different autoloaders in there if you want and PHP will go through them one by one (in the order you defined them) using each function to try and load a class. However, a couple convention based autoloaders is a bit cleaner and more of a preferred method. Also keep in mind that the autoloader translates both namespace separators \ and underscores _ as a directory separator. So your Front_controller.php would not autoload as you would expect.
The code below will help. But I'll advice you check on Namespaces.
spl_autoload_register ( function ($class) {
$sources = array("Controllers/$class.php", "Lib/$class.php ", "Models/$class.php " );
foreach ($sources as $source) {
if (file_exists($source)) {
require_once $source;
}
}
});
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!