What is best possible approach to autoload classes from a PHP Project which is residing in
PHP Project
C:
|Projects
|MyProject
|Classes
|CStudents.php
|Student (ClassName)
|getStudentName() (Method)
All the classes have prefixes, such that, if the class is Students then it resides in CStudents.php
Right now I need to access these classes pull out some data and further with the Zend Framework 2 modules.
Zend Framework 2 Project:
C:
|Projects
|Zend
|module
|Application
|Module.php
So what would be the simple and best possible approach for this. I need to autoload not more than 50 Classes.
EDIT: My question is almost similar to this one, but the only difference is that I have the requirement for Zend Framework 2.
As mentioned all Classes are residing in Classes folder, Class files have "C" [CStudent.php] as prefixes and the class names [Class Student]start without the prefixes, so lets say I want to access Student::getStudentName(); How can I accomplish that?
Thanks
Here is an example of how I use the Autoloader.
Module.php
/**
* Autoloader
*
* #return array
*/
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\ClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php'
)
);
}
ZF2 comes with a classmap_generator.php which will build the required PHP Array of all the classes found in your Module. You can run classmap_generator -l modules/NameOfYourModule.
This will output a file called autoload_classmap.php and place it inside of your Module/NameOfYourModule folder for you.
You can also find a lot more information in the documentation http://zf2.readthedocs.org/en/latest/modules/zend.loader.autoloader-factory.html
Related
I want to ask some questions about the Zend framework. if someone knows please answer it will be a great help.
Q1. Can we create classes, abstract and derived classes in any folder
of the Zend Project?
Q2. If Q1 answer is yes how we can database access (from the model
class) or we need to utilize any other Zend related functionality.
Q3. Is it possible to place abstract class and the implementation
of an class within a dedicated folder somewhere within the source
tree?
Q1 - Can we create classes, abstract and derived classes in any folder of the Zend Project?
Yes, you can, but it is not encouraged. Why? Because it would end up in a messy project, with a portion of code in a given location, other code somewhere else, other snippets in a third location.. This will make maintenance more complex than it should be, wasting time searching for the code between all different locations.
For this subject, I suggest you to read the PSR-4 specifications and directives
That being said, let's make this example. You want to create a class OutsideClass, with namespace OutsideCode, in folder outsideFolder.
What you need to do is:
Create in the folder outsideFilder, which will be located in the root folder of your project.
Create the class OutsideClass:
<?php
namespace OutsideCode;
class OutsideClass
{
// ...
// Class properties, constructor and methods
// ...
}
Add the namespace inside the composer.json, so the application will be able to translate a namespace into a phisical location:
"autoload": {
"psr-4": {
...
"OutsideCode\\": "outsideFolder/"
}
}
Run composer dump-autoload to recreate autoload file
End. You can now put all the code you want inside this folder, always respecting PSR-4 directives
Use your new classes from your controller/mappers/forms/validators/...
<?php
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use OutsideCode\OutsideClass;
class IndexController extends AbstractActionController
{
public function indexAction()
{
$outsideClass = new OutsideClass();
}
}
Q2 - If Q1 answer is yes how we can database access (from the model class) or we need to utilize any other Zend related functionality.
It is not mandatory to use Zend related functionalities.
Nobody prevents you to access your write all your code from scratch, using only PHP methods, to access the database, or to validate a phone number, or to send an email. If you want to use Zend functionalities (or classes that you already wrote), just import them with a use statement and the top of the file (as shown in the previous snippet).
The most important thing is always: DRY and don't reinvent the wheel (+this)
Q3 - Is it possible to place abstract class and the implementation of an class within a dedicated folder somewhere within the source tree?
Yes, until its position follows PSR-4 specifications and directives, otherwise it won't be loaded (nor executed)
I am just starting to look at Zend Framework 2 (and am new to ZF in general), and in the user guide, they are using autoloading when adding a new module. However, I find the explanation to be quite challenging for a rookie. They are adding a Module.php file within the module directory, which among others contains the following code:
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\ClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php',
),
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
Now I did some digging around to try and figure out what this autoloading is all about. As far as I understand, the autoloading uses spl_autoload_register() and is a way to avoid having require_once() everywhere in the code. So, when trying to use a class that is not defined, the autoload() method that was registered will be run, which simply does an array lookup and includes the file like below if it was added.
// Zend/Loader/ClassMapAutoloader.php
public function autoload($class)
{
if (isset($this->map[$class])) {
require_once $this->map[$class];
}
}
This seems clever due to performance. I hope what I just wrote is correct. Based on this, I am trying to figure out what is going on in getAutoloaderConfig() from the first code snippet, but I am quite confused. It seems as if the array that is returned by this method is used for AutoloaderFactory::factory(), but I am not sure for what purpose. Instantiating autoloaders with options it seems, but exactly what that does, I am not sure. I guess the second entry of the array specifies where to find the source files for the module's namespace - at least that would be my guess. The first entry I am, however, not sure about. In the user guide, it says the following:
As we are in development, we don’t need to load files via the classmap,
so we provide an empty array for the classmap autoloader.
The file just returns an empty array. I am not sure what the purpose of this ClassMapAutoloader.
Sorry if my point is unclear; basically I am trying to figure out what is happening in getAutoloaderConfig() and what mymodule/autoload_classmap.php is used for. If someone could shed some light on this, that would be much appreciated!
The classmap is there to show PHP the most direct way to a class. It's essentially saying "You you're looking for A\Class\Youre\Looking\For, look no further than this file: xyz.php. This would be expressed like this:
return array(
'A\Class\Youre\Looking\For' => ___DIR__.'/xyz.php'
)
Without it PHP has to run through the whole autoloader chain, which can be pretty expensive. Why is it saying something about "as we're in development"? Because classmap files are typically generated on the production server by some script. Basically, just don't worry about it too much right now. It's micro-optimization...
The getAutoloaderConfig() method is just there to give you some flexibility in really advanced applications. Most of the time you can just use the SkeletonApplication's and SkeletonModule's boilerplate code and leave it alone. Really, you can even kill the 'Zend\Loader\ClassMapAutoloader' => array(__DIR__ . '/autoload_classmap.php',) part for now.
It's just a hook for future improvements and nothing to worry about too much if you're just starting out with ZF2 (like me ;).
ZF2 has a number of autoloaders available.
The 2 most common (or the 2 which developers interact with directly at any rate) are Zend\Loader\ClassMapAutoloader and Zend\Loader\StandardAutoloader.
The classmap autoloader is usually used at the module level to
provide a simple but fast array lookup mechanism. It is configured
with an associative array of key => value pairs, with the key
representing the class, and the value representing the filename
which defines the class.
The standard autoloader, on the other hand, is designed to hold a
list of "namespaces" and base directories. What is does is to then
build the path to the class referenced, but not yet loaded, by
prepending the base directory path for that namespace to the class
name, to arrive at the final absolute path to the class file, which
it then tries to include. You can quickly populate the
classmap_autoload.php file by running either
/path/to/ZF2/bin/classmap_generator.php or zftool.phar generate
classmap.
Zend\Loader\AutoloaderFactory is designed to manage the various autoloaders, and to make sure there are no conflicts. Ultimately, of course, all autoloading capabilities leverage PHP SPL autoloading.
The purpose of getAutoloaderConfig() is to identify to the autoloader factory which autoloaders are available for this module's namespace.
In the example shown above, that would be, in order of preference, the classmap autoloader, followed by the standard autoloader. If you don't wish to use the classmap autoloader for that module, simple remove the reference from the array returned by getAutoloaderConfig().
The method name getAutoloaderConfig() is reserved. If this method is defined, during the module initialization process, a listener (Zend\ModuleManager\AutoloaderListener) is attached which retrieves the configuration returned by this method, and adds it to the consolidated configuration.
A web application consists of many PHP classes, and
each class typically resides in a separate file. This introduces
the need of including the files.
As your application grows in size, it may be difficult to include
each needed file. Zend Framework 2 itself consists of hundreds of files,
and it can be very difficult to load the entire library and all its
dependencies this way. Moreover, when executing the resulting code, PHP interpreter will
take CPU time to process each included file, even if you don't create an
instance of its class.
To fix this problem, in PHP 5.1, the class autoloading feature has been introduced.
The PHP function spl_autoload_register() allows you to register
an autoloader function. For complex web sites, you even can create
several autoloader functions, which are chained in a stack.
During script execution, if PHP interpreter encounters a class name
which has not been defined yet, it calls all the registered autoloader functions
in turn, until either the autoloader function includes the class or "not found" error is
raised. This allows for "lazy" loading, when PHP interpreter processes the class
definition only at the moment of class invocation, when it is really needed.
Because each library's vendor uses its own code naming and file organization conventions,
you will have to register a different custom autoloader function per each dependent library,
which is rather annoying (and actually this is an unneeded work). To resolve this problem,
the PSR-0 standard was introduced.
The PSR-0 standard
(PSR stands for PHP Standards Recommendation)
defines the recommended code structure that an application or library must follow
to guarantee autoloader interoperability.
Each module of the web application registers an autoloader, which makes it possible to autoload
any PHP class in your modules. This is made with the getAutoloaderConfig() method of the Module class.
ZF2 has a special component named Zend\Loader, which contains implementations
of the two commonly-used autoloader classes: the standard autoloader (Zend\Loader\StandardAutoloader)
and class map autoloader (Zend\Loader\ClassMapAutoloader).
The fact that ZF2-based application modules conform to PSR-0 standard makes it possible to use the standard autoloader.
The class map autoloader can be used as a faster replacement for the standard autoloader.
This autoloader expects you to pass it a class map array. Each key=>value pair of the class
map is, respectively, the class name and path to the PHP file containing the class.
The concept of autoloading in Zend Framework 2 is well explained in Using Zend Framework 2 book.
I have a file (an xmlrpc library for PHP) that I would like to use into a Symfony2 class (so inside a Symfony2 project).
I can't use autoloader because as written here
which is able [the autoloader] to load classes from files that
implement one of the following conventions:
1) The technical interoperability standards for PHP 5.3 namespaces and
class names;
2) The PEAR naming convention for classes.
If your classes and the third-party libraries you use for your project
follow these standards, the Symfony2 autoloader is the only autoloader
you will ever need.
the class that I'll go to use, didn't satisfies one of those requirements.
So if I can't autoload that file, since isn't possible (as I understand, but I can go wrong) to use require_once (or simply require) with namespace, what is the solution for this issue?
Assuming you have a file named xmlrpc.lib.php with the following content:
<?php
class XMLRPC_Server {
// ...
}
class XMLRPC_Request {
// ...
}
class XMLRPC_Response {
// ...
}
You can create an instance of MapClassLoader to handle it's autoloading:
// Create map autoloader
$mapLoader = new MapClassLoader(array(
'XMLRPC_Server' => __DIR__.'/../library/xmlrpc.lib.php',
'XMLRPC_Request' => __DIR__.'/../library/xmlrpc.lib.php',
'XMLRPC_Response' => __DIR__.'/../library/xmlrpc.lib.php',
));
// Register autoloader
$mapLoader->register();
When one of these classes will be auto-loaded, others will be auto-loaded too because they share the same PHP file.
Which folder should I put strategy objects, or any objects that are not domain models? I'm using Zend Framework, if that matters. Appreciate it!
I would use the recommended folder structure laid out here in the Zend Programmer's Reference Guide and place them into the modules folder.
Two pretty standard options:
Place this code into the library folder. Typically a file library/App/SomePackage/SomeClass.php wouldcontain the class App_SomePackage_SomeClass. Just add the line autoloadernamespaces[] = "App_" into your configs/application.ini file.
Create a new folder inside your application folder and configure a Zend_Loader_Autoloader_Resource (or its extended class Zend_Application_Module_Autoloader) with appropriate appnamespaces, paths, and prefixes.
Using this second approach could go something like this:
protected function _initResourceLoader()
{
$resourceLoader = Zend_Application_Module_Autoloader(array(
'namespace' => 'Application_',
'basePath' => APPLICATION_PATH,
));
$resourceLoader->addResourceType('strategy', 'strategies', 'Strategy');
}
Then a class named Application_Strategy_SomeClass would reside in the file application/strategies/SomeClass.php.
Noe that using Zend_Application_Module_Autoloader - instead of the more generic parent Zend_Loader_Autoloader_Resource - will give you a standard set of autoloader mappings for models, forms, services, view helpers, etc.
I've started to document myself regarding Zend Framework as I will soon start using it in production. Everything was working fine, until I started to use and work with models :).
The default location for models, based on Zend recommendations, is application/models/DbTable, where all the models will be thrown in. This location forces me to name a model like Application_Model_DbTable_Actors. For me, this is a very long name for a model and not a easy to use one.
The directory structure that I want to obtain looks something like this:
application/
models/
actors/
ActorsMapper.php
Actor.php
books/
BooksMapper.php
Book.php
etc.
So all my models will reside under the models directory, but grouped in their own directories.
Naming for each class should be ActorsMapper or Actor (They will both extend Zend_Db_Table or Zend_Db_Row).
I am aware of the fact that in my controllers if I instantiate a model using something like $actors = new ActorsMapper() I will get a Fatal error: Class not found and that why I'm asking for your help with this.
To solve this issue I tried to add my models directory to the include_path:
first try
added includePaths.models = APPLICATION_PATH "/models" to application.ini
but this one doesn't even add it to the include path
second try:
explicitely added the path using set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
realpath(APPLICATION_PATH . '/models'),
get_include_path(),
)));
but even if this adds that path among the included ones, the error still persists.
I've seen this naming of models in the official documentation of the Zend_Db_Table, but I couldn't find anything related to autoloading them.
Thank you all for any solutions.
p.s. zend framework version is 1.11.1
Zend Framework has a build in autoloader. It works by mapping the class name to the directory tree, so Application_Model_Actors_Actor will get mapped to
Application\
Models\
Actors\
Actor.php
Unfortunately, you cannot change this. The feature you are looking for is namespacing but it is only supported (and is in fact one of the major features) of Zend Framework 2 which is still being developed.
Try to extend Zend_Application_Bootstrap_Bootstrap then you can try this one
$loader = $this->getResourceLoader();
$loader->addResourceType('books', 'models/books', 'Model_Book');
$loader->addResourceType('actors','models/actors','Model_Actor');
I am also trying to implement this kind of implementation in a observer pattern.