Autoloading both Classes & Models - php

I know it's common practice to autoload your controllers when using an MVC framework. I have made my own mini-framework where controllers are autoloaded fine.
Are there any security/bad issues with having the same autoload function load the models too?
I.e.
function __autoload($className) { // Autoload both controllers and models.
if(stristr($className, 'Model'))
{
if (is_readable(Ms . $className . '.php')) {
include Ms . $className . '.php';
}
} else {
if (is_readable(Cs . $className . '.php')) {
include Cs . $className . '.php';
}
}
}

You could use namespaces and spl_autoload_register() in order to get such an autoloader. There's no specific security issues regarding a multi autoloader (an autoloader for multi classes of classes) rather than a controller-only autoloader.
I usually works with namespaces like:
$home = new controller\home;
$home->actionIndex();
$users = new model\users;
$post = new view\post;
from there it's easy to replace a \ in the class name with a / to get the specific paths for the file (obviously doing the needed security checking as always).

Related

Namespaces and Class loading in php

I'm new to namespaces in PHP and trying to make use of them to load classes.
Whenever I run my code I get class Cheese cannot be found on line x
PHPstorm recognizes the class via the namespaces and enables its methods.
I have the following files / directory structure.
/Project
/App
Mouse.php
/Test
MouseTest.php
Mouse.php
namespace App\Mouse;
class Cheese
{
}
MouseTest.php
namespace Test\MouseTest;
use \App\Mouse\Cheese as Cheese;
class CheeseTest
{
function test() {
$cheese = new Cheese();
$cheese->eat();
}
}
if you use composer or any autoloader that follow psr-0, then file name must same with class name, change Mouse.php to Cheese.php
This looks like a similar structure to the PSR0 standard found here: http://www.php-fig.org/psr/psr-0/
This is an example autoloader following that structure:
function autoload($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;
}
spl_autoload_register('autoload');
The spl_autoload_register call registers the autoload function so when a class is instantiated, it will use your autoload function to retrieve the class definition.
PHP namespaces don't load classes automatically, you have to include their files.
To make it automatic (like you want) you have to make an autoloader which will load the classes depending on the namespaces that you want to use.
The best way to make this, is using composer: http://code.tutsplus.com/tutorials/easy-package-management-with-composer--net-25530
but I recommend to search "php auloader" in google

How can i manage my dependencies?

i'm working on a likely a large PHP project where i have too many classes, and my problem appears when some classes depends on others, for example the error-handling class may depend on the security class, the user class may depend on the database class and so on...
$obj1 = new class1();
$obj2 = new class2($obj1);
$obj3 = new class3();
$obj4 = new class4($obj3 , $obj1);
etc...
hence my quesion comes in! what is the best way to manage dependancies ?
Try autoloading your classes. That way if a class needs another class, it doesn't have to require() it.
http://php.net/manual/en/function.spl-autoload-register.php
Example from the documentation:
<?php
function my_autoloader($class) {
include 'classes/' . $class . '.class.php';
}
spl_autoload_register('my_autoloader');
// Or, using an anonymous function as of PHP 5.3.0
spl_autoload_register(function ($class) {
include 'classes/' . $class . '.class.php';
});
?>

PHP Namespaces autoload

I have the following directory structure:
/var/www/Project1/Project1.php
/var/www/Project1/User/UserProfile.php
Inside Project1.php:
<?php
namespace Project1;
set_include_path( __DIR__ );
spl_autoload_extensions('.php');
spl_autoload_register();
use User\UserProfile;
$u = new Avatar();
...
?>
Inside UserProfile.php:
<?php
namespace Project1\User;
class Avatar{
}
...
?>
When I execute php Project1.php I get:
PHP Fatal error: spl_autoload9(): Class User\UserProfile could not be loaded
I don't see the problem.
spl_autoload_register(); when called with no params will just register the default autoloader which fails to handle namespaces with your project layout. You'll have to register your own method to make it work. Like this:
spl_autoload_register('my_autoload');
And here comes the autoload function. This function expects the classes to be stored in a way like:
/path/to/project/Namespace/Classname.php
/path/to/project/Namespace/Subnamespace/Classname.php
You can name the classes like \Namespaces\Classname or the old style way Namespace_Classname:
function my_autoload ($classname) {
// if the class where already loaded. should not happen
if (class_exists($classname)) {
return true;
}
// Works for PEAR style class names and namespaced class names
$path = str_replace(
array('_', '\\'),
'/',
$classname
) . '.php';
if (file_exists('/path/to/project/' . $tail)) {
include_once 'path/to/project/' . $tail;
return true;
}
return false;
}
Note that the function is taken from my github package Jm_Autoloader. The package provides more functionality as multiple include paths, path prefixes and static autoloading (with a predefined assoc array class name => file name). You can use it if you like ;)

Lazy loading, am I doing this right?

I'm writing API implementation and my main API class has __call() magic method:
public function __call($name, $params)
{
if (in_array($name, $this->resources))
{
require_once APPPATH . 'resources' . DIRECTORY_SEPARATOR . $name . '.php';
$class_name = ucfirst($name);
return new $class_name($params);
}
}
So basically in my application if I write
$api->product()->get($product_id);
// or
$api->product()->post($product);
resources/product.php file is included, Product object created and appropriate method called. Is this a correct way to do lazy loading and is there a better way to implement an API?
You can add your own autoloader afterwards. If "first" autoloader does not find file you have maybe a second logic for it or a third...
spl_autoload_register(); #http://www.php.net/manual/en/function.spl-autoload-register.php
In that situation you dont have to care about your frameworks/applications autoloader.

Zend_Framework - Class naming

I wanted to use code like this in my Zend Framework project:
public function indexAction() {
$user = new User();
$user->name = "Guest";
$user->save();
}
The main thing that is important for me is that the class is called just User and not App_Model_User but how could I manage that?
I thought I could add the path to the file User.php in the model-folder to the include_path:
<?php
class User {
/* Some code */
}
But how could I config the autoloader to load that file/class?
Currently I'm using the autoloader with the appnamespace ("App") to load classes called App_Model_User which works but the class naming is not the right I think. It should be cleaner and clearer.
I use set_include_path as follows:
$root = dirname(dirname(__FILE__));
set_include_path(
$root . '/application' . PATH_SEPARATOR
. $root . '/library' . PATH_SEPARATOR
. $root . '/application/models' . PATH_SEPARATOR
. $root . get_include_path()
);
Then the autoloader picks up any models (with any name) which I put in /application/models. The above is in my only public facing script (index.php). This is how I set up the autoloader:
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->setFallbackAutoloader(true);
The second line will ensure that your models do not have to be explicitly included. See:
http://framework.zend.com/manual/en/zend.loader.autoloader.html
What is your version of PHP? You can use namespaces.

Categories