Requiring classes in Zend Framework based library - php

Simple question. Why use require_once to include classes that you use within a file? For example, if I create a class that extends Zend_Db_Table_Abstract, I don't really need to have this in the class declaration file:
require_once "Zend/Db/Table/Select.php";
They are included by the auto-loader anyway. Is there a performance gain for explicitly declaring the "imports"? Is it for unit testing?

Simple Answer: If you aren't using the autoloader, the functionality will not break.
Its not necessary to do this in your project if you know for a fact you will be using the autoloader, but if you are working on a framework (like Zend) that will be used by other developers as well, you will want to have re-usability with least amount of compatibility issues, therefore you really should require explicit dependencies.
Another benefit is that it helps you see when your classes are becoming dependent on too many other classes. This helps you keep your coupling to a minimum while designing your objects.
An example from Zend/Db/Table/Select.php
/**
* #see Zend_Db_Select
*/
require_once 'Zend/Db/Select.php';
/**
* #see Zend_Db_Table_Abstract
*/
require_once 'Zend/Db/Table/Abstract.php';

You can get rid of these calls in your IDE by replacing "require_once" with "// require_once" require_once should be used only for class loading. Other, for example inserting an array from file like $file = include "test.php";, don't use it (or don't need to use it).

Related

Proper way to include SPL Class Loader

Problem
I am using the SPL Class Loader provided by PSR Group. However, I've come to a chicken-egg paradox.
That is, this will autoload classes preventing explicitly including them. But I first need to include/require this class and the code for instantiating the object
$classLoader = new SplClassLoader('Doctrine\Common', '/path/to/doctrine');
$classLoader->register();
Question
What is common solution for including the autoloader code?
In the case of a front-end controller, I could add the code there. But I'm not always using the front-end controller patter. I suppose I could also use PHP's auto_prepend_file. Interested in the communities input.
You explicitly require the autoloader on the bootstrap stage (the stage where the application is started up).
All subsequent functions/classes are then autoloaded.

What is the right way to load dependencies in PHP?

I have a doubt about the right way/best practice about loading dependent classes in PHP.
I usually put all dependencies in the beginning of each class with a include_once in a way similar to Java imports. Something like:
include_once 'dto/SomeObjectDTO.php;'
include_once 'dao/SomeObjectDAO.php;'
include_once 'util/SomeObjectUtil.php;'
class SomeObjectService{
#class code here
}
This is the best way to load classes? Or maybe load all classes in a Bootstrap.php? Other ways?
Note that I'm talking about loading my own classes, not complex external classes like frameworks.
Like Homer6 said, autoloading is a php's built in dependency loading mechanism.
PHP-FIG proposed a family of PHP coding standards called PSR. PSR-0 deals with class naming and autoloading. Here are some links:
Requirements and an example autoloader
A good article on the subject
Also, keep in mind, that autoloading comes with a price. There is a lot of string work and work with the fs in the proposed default autoloader(you can implement your own faster autoloader, but it is not going to conform to the standard). This makes autoloading slow when you need to load a lot of classes. So if you needed to load 2 classes only, your approach would be faster and more understandable.
Since version 5.3 PHP supports namespaces.
This allows you to have a package and class hierarchy just like you know them from C++ or Java.
Check out those resources to learn more:
http://www.php.net/manual/en/language.namespaces.basics.php
http://php.net/manual/en/language.namespaces.importing.php
PHP's you can register your autoload method. Symfony 2 contains a nice class to do it with.
http://php.net/manual/en/function.spl-autoload-register.php
I've adapted it to work with the library that we've written.
https://github.com/homer6/altumo/blob/master/source/php/loader.php
https://github.com/homer6/altumo/blob/master/source/php/Utils/UniversalClassLoader.php
This adaption allows you to have namespaces that do not require the top level namespace to have the same folder name.
set_include_path(get_include_path()
. PATH_SEPARATOR . 'path1'
. PATH_SEPARATOR . 'path2'
);
// auto load classes:
function autoloadClasses($className) {
require_once $className . '.php';
}
spl_autoload_register('autoloadClasses');

Why does Codeigniter assume I want to create an instance of the class when using $this->load?

In Codeigniter, when we use $this->load('class_name') in the controller, CI will try to create an instance of the class/model using its constructor.
But sometimes, I don't actually need an instance from that class, I just want to call some static functions from it. Also, there is a big limitation with $this->load('class_name'), it does not allow me to pass parameters to the constructor (unless we extend or modify the core class of CI).
I think the $this->load('class_name') function should only do a require_once on the class php file for me, and let me freely do things (create instance/call static functions) with the class in the controller.
Should I simply ignore this function and use require_once or writing my own __autoload function to load up the classes? This way, I just feel strange because it seems I am not writing codes inside the CI box.
You can pass parameters to your constructor. See the "Passing Parameters When Initializing Your Class" section in the user guide.
I found CodeIgniter's object creation and loading to be very limiting. I want full control over my code, and little magic in the background. I have instead started using Doctrine's Class Loader. It's very lightweight and is essentially SPL autoloading (also a good alternative). You don't need the whole Doctrine shebang with ORM and all that stuff, just the ClassLoader. There's some configuration tinkering to get this right, but it works wonders.
With PHP 5.3 I now have namespaced classes in the Application directory. For instance I created a new class in the Tests directory: Application\Tests\SomeTest.php
That test could look something like this:
namespace Tests;
class SomeTest {
...
}
I would use this class in my code (controllers, views, helpers) by simply using the fully qualified namespace (i.e. $test = new \Tests\SomeTest) or a "use" statement at the top of my code (use \Tests\SomeTest as SomeTest).
In this way I intend to replace all libraries and models with OO namespaced variants. There are many benefits to this: fast autoloading with SPL, full IDE intellisense support for classes/methods (CodeIgniter is really bad for that), your code is more portable to other frameworks or projects.
That said, I still use a lot of the CodeIgniter engine. This basically means I have $CI =& get_instance() in most of my classes. It's still a work in progress and I think the main reason I need CI is for it's database access. If I can factor that out ... and use something like Dependency Injection, then I won't need CodeIgniter in my classes at all. I will simply be using it for it's MVC framework, and using it's methods occasionally in my controllers.
I know this goes above and beyond your question, but hopefully it's some food for though - and it helps me to get it in writing too.

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.

ZF Autoloader to load ancestor and requested class

I am integrating Zend Framework into an existing application. I want to switch the application over to Zend's autoloading mechanism to replace dozens of include() statements.
I have a specific requirement for the autoloading mechanism, though. Allow me to elaborate.
The existing application uses a core library (independent from ZF), for example:
/Core/Library/authentication.php
/Core/Library/translation.php
/Core/Library/messages.php
this core library is to remain untouched at all times and serves a number of applications. The library contains classes like
class ancestor_authentication { ... }
class ancestor_translation { ... }
class ancestor_messages { ... }
in the application, there is also a Library directory:
/App/Library/authentication.php
/App/Library/translation.php
/App/Library/messages.php
these includes extend the ancestor classes and are the ones that actually get instantiated in the application.
class authentication extends ancestor_authentication { }
class translation extends ancestor_translation { }
class messages extends ancestor_messages { }
usually, these class definitions are empty. They simply extend their ancestors and provide the class name to instantiate.
$authentication = new authentication();
The purpose of this solution is to be able to easily customize aspects of the application without having to patch the core libraries.
Now, the autoloader I need would have to be aware of this structure. When an object of the class authentication is requested, the autoloader would have to:
1. load /Core/Library/authentication.php
2. load /App/Library/authentication.php
My current approach would be creating a custom function, and binding that to Zend_Loader_Autoloader for a specific namespace prefix.
Is there already a way to do this in Zend that I am overlooking? The accepted answer in this question kind of implies there is, but that may be just a bad choice of wording.
Are there extensions to the Zend Autoloader that do this?
Can you - I am new to ZF - think of an elegant way, conforming with the spirit of the framework, of extending the Autoloader with this functionality? I'm not necessary looking for a ready-made implementation, some pointers (This should be an extension to the xyz method that you would call like this...) would already be enough.
To extend what Gordon already pointed out, I'd create my own autoloader class that implements Zend_Loader_Autoloader_Interface and push that onto the Zend_Loader_Autoloader-stack.
class My_Autoloader implements Zend_Loader_Autoloader_Interface
{
public function autoload($class)
{
// add your logic to find the required classes in here
}
}
$autoloader = Zend_Loader_Autoloader::getInstance();
// pushAutoloader() or unshiftAutoloader() depending on where
// you'd like to put your autoloader on the stack
// note that we leave the $namespace parameter empty
// as your classes don't share a common namespace
$autoloader->pushAutoloader(new My_Autoloader(), '');
I wouldn't go with the Zend_Loader approach as, even though not deprecated yet, the new Zend_Loader_Autoloader seems to be best practice currently.
See the manual on Zend_Loader:
By default, the autoloader is configured to match the "Zend_" and "ZendX_" namespaces. If you have your own library code that uses your own namespace, you may register it with the autoloader using the registerNamespace() method.
$autoloader->registerNamespace('My_');
Note that the autoloader follows the ZF Naming Convention, so Zend_Foo_Bar will look in Zend/Foo/Bar.php.
However,
You can also register arbitrary autoloader callbacks, optionally with a specific namespace (or group of namespaces). Zend_Loader_Autoloader will attempt to match these first before using its internal autoloading mechanism.
$autoloader->pushAutoloader(array('ezcBase', 'autoload'), 'ezc');
Another way would be to create custom class Loader extending Zend_Loader and then register it with:
Zend_Loader::registerAutoload('My_Loader');
ZF will then use this autoloader instead of the default one.

Categories