class overrides and rewrites with namespace psr-4 - php

i've worked with older php frameworks such as magento 1.x line where class rewriting (other then by core/community/local overrides) is done using framework config and framework getModel() or getSingleton() like calls, that have the opportunity to check the config before loading the class.
in other words, it could very well be that the config is loading a class under a completely different name not just path.
my question is, how could rewrites like this be supported in a newer psr4/composer aware framework where classes are instantiated directly with the new keyword instead of some getModel() call?
you could perhaps put the config checks directly into the autoloader instead of using a method to get the class, but then what about composer libs, using their own autoloaders like vendor/autoload.php? just chaining the autoloaders would give a hit on the wrong class if the rewrite uses another class name and both exists.
some link or explanation on how to perform both overriding (as in core/community/local) and rewrites (as in config myClassName -> newClassName) using newer namespace, psr4 & composer aware techniques would be most welcomed.

Related

How does the PHP 'use' keyword work (in Symfony 2)?

In Symfony 2, all requests are getting routed through app_dev.php (or app.php).
The first few lines look like:
<?php
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Debug\Debug;
...
In theory, I get that this just imports the specified namespace (or class) to the current scope. What I don't understand is how PHP maps this to a file. For example, the Debug class is located in:
vendor/symfony/symfony/src/Symfony/Component/Debug/Debug.php
How does PHP know to look in vendor/symfony/symfony/src/?
I'm probably misunderstanding what is happening, but any clarification would be appreciated.
Knowing which file a class lives in isn't the job of the language, it's the job of the autoloader.
All the use keyword does is this instance is create an alias:
use Symfony\Component\HttpFoundation\Request;
This is saying in the following script, when I refer to Request I really mean Symfony\Component\HttpFoundation\Request. If I use Request object in some way (by either creating an instance or calling a static method on it) then the autoloader will go and try to load the file that class is defined in if it hasn't been loaded already.
The inner workings of the autoloader, though, is different from project to project. There has been a move to standardize autoloader behavior à la PSR-4, but there's nothing in the language saying that you have to adhere to that standard. You could, for instance, have a scheme where all class files reside in a single directory and your autoloader just loads all classes from there, regardless of what namespace they're in.
That scheme would suffer from the fact that you could only have a single class of every name, but there's nothing stopping you from doing it that way.
To answer your question: "How does it know that "Symfony\Component\Debug\Debug" is a valid namespace?"
It doesn't, because it's not actually going out and trying to load that class at this point. If in any random PHP script you put something like this at the top:
use \Non\Existant\ObjectClass;
But don't ever actually use ObjectClass anywhere, you will get no errors. If you try to say new ObjectClass, though, you will get a class not found error.
Simplistically speaking, you have to load all the files beforehand into memory for PHP. PHP does not inherently have any standards to where files are located, the rules for loading files has to be done by your code.
When PHP attempts to load a file, it will check its memory if the class definition exists, if not it will attempt to autoload the file that may contain your class definition; see PHP: Autoloading Classes and spl_autoload_register
Some common autoloading strategies have been defined by the PHP Framework Interop Group:
PSR-0 (Autoloading standard)
PSR-4 (Improved Autoloading standard)
In this case, autoloading is done by Composer, all you need to do is include vendor/autoload.php in any of your scripts and vendor code downloaded via composer can be autoloaded. You can manually add classes into the composer autoloader as well. See: Composer Autoloading

include on instantiate PHP

Well I have a question. On Zend Framework We use a very interesting structure because if you intanciate a class then automatically Zend include the class file and after instanciate it (Class obviously allow to ge the directory's structure Class: abc_def_pqr then path is abc/def/pgr.php)
Does anyone have any idea???
Zend Framework uses spl_autoload_register to register a function that is called when a class is called but does not exist.
The function then does as you say, replace the underscores with directory separators and tries to include the file.
See Autoloading Classes but note using spl_autoload_register instead of __autoload allows for multiple autoload functions, which is better practice. Especially if being used in conjunction with ZF or external libraries.

Is registering the autoloader needed zend_loader::registerAutoload()

I'm guessing this line registers the autoload function, which in turn loads needed Zend classes.
Zend_Loader::registerAutoload();
My question: is this line meant to be used in applications that call some zend components but aren't fully zend applications? or is needed also in applications that are fully zend and use zend MVC?
Well, first we should note that Zend_Loader::registerAutload() is deprecated (since 1.8.0). Better is:
Zend_Loader_Autoload::getInstance();
What this does is register an SPL __autoload($classname) function that attempts load classes when they are called for but not-yet-loaded. The default behavior of this autoloader in a non-framework application is to map a class name to a file name (relative to the currently defined include_path) and include() that file in the hopes that the requested class will be defined there.
The specific mapping uses the PEAR 1-class-1-file convention in which a class named something like My_ComponentName_ClassName will reside in the file My/ComponentName/ClassName.php.
See this answer for more details.

Selective PHP autoload

I am writing a add-on module which is integrated with an existing PHP application; Because I am using a MVC pattern, and which may requires lot of inclusion of classes (which might not be used at all depending on the action of the user), I decide to use autoloading of classes.
However, I have to ensure that the autoload function does not interferes with the normal operations of the existing applications.
Does autoload only kicks in if a class name is not defined?
Say I have to write another module which uses its own autoload functions (say, I have an autoload for a module, since they each reside in their own folder), how do I differentiate which module is it for?
For #2, I thought of 2 options. Either prefix the class name with the module name (Such as 'MyNewModule_View_Default' and 'AnotherModule_View_Default'), or use file_exists to check the include file exists.
Other suggestions are welcomed too!
Just check if the class that is to be loaded already exists with class_exists() before actually loading it in your autoloader implementation. Especially if you have multiple registered autoloaders (see 2).
You can specify multiple autoloaders in a stack via spl_autoload_register(). The registered functions are executed in the order in which they where registered until the class is successfully loaded. You can specify different autoloaders for different modules for example. Or you can do a namespacing approach like in the Zend_Framework, if you have control over class names.
Yes, autoloader is only called when class name is not found.
Usually you'd check the class' namespace (pre 5.3 you use pseudo-namespaces, usually separated by an underscore). So your autoloader would only load classes that are under the namespace(s) of your application.

Controller folders and the new Autoloader in Zend Framework

After introduction of Autoloader, I started to port existing ZF app.
The immediate error was that IndexController was extended by BaseController,
which is now cannot be found, although it resides in application/controllers folder, with other controllers.
Does the autoloader paradigm require that BaseController is renamed to My_BaseController and put into library folder? On the other hand, it's so nice to keep all controllers in one folder with a BaseController.
The module autoloader does not load from the Controller's folder by default. You can either add the folder to the included Module autoloader or create your own resource autoloader.
See http://framework.zend.com/manual/en/zend.loader.autoloader-resource.html#zend.loader.autoloader-resource.module for info on the Resource / Module autoloader.
You could do things the old fashioned way though and just require_once('BaseController.php');
I haven't actually seen anything use application/controllers before
Generally, stuff would go into application/modules/<module>/controllers/ where "generic" controllers would go into the default module
You might get a better answer if the above is incorrect if you mention what versions your transitioning between, and how you're trying to call the controller?

Categories