I'm new in Laravel, I got a quest about helper (psr4 autoload class) & trait
I create a autoload class, connect to api and do various things.
My question is what's different between this and trait?
I can use trait to do all the same things
A trait is used to create small items of re-usable code which can be shared between multiple classes. They exist generally because you can only extend one class at at time in PHP. You use a trait, if for instance, you had a function or set of functions which would be useful in more than one class.
Laravel uses Composer which uses the PSR-4 standard of autoloading (amongst others), this simply means that you don't have to worry about using require, include or anything else to make the contents of a file available.
A trait is a specific set of re-usable functionality which you can attach you whatever entity only with the limitation that it needs to have no dependencies from the class you're using the trait from.
The helper file usually contains global functions that can be useful everywhere, like comparison functions, or even just shortcuts to IoC injected classes.
if (! function_exists('clock'))
{
function clock()
{
if (class_exists(Clock::class)) {
return app()['clock'];
} else {
return false;
}
}
}
Related
How can I add a static method for all classes of my php using an class Class or class Object (meta class) like
class Object //meta class, all classes php henerit of it
{
static function test() { return 42; }
}
now if I make a new class like :
class User
{
}
I want to be abble to write :
User::test();
same with all classes I will write
PHP has no concept of metaclasses; the way in which classes themselves behave is essentially hard-coded into the language. (You could argue that internal classes written in C conceptually use a different metaclass than userland classes written in PHP, since they can implement a different set of hooks; but that's not a distinction that's visible in the language, and not really relevant to your example.)
It also has no universal base class; there is no "Object" or "Any" or "Mu" class which all other classes implicitly or explicitly inherit from.
More importantly, there is no way to add to an existing class; there is no way to "re-open" or "monkey-patch" a class, or add methods via "extension classes". So even if there was a default metaclass or universal base class, you wouldn't be able to change it. Any classes you wanted extra behaviour on would have to opt-in to being instances of a non-default metaclass, or inherit from a non-default base class.
It's not clear exactly what the use case is, but there are a number of things you can do:
Write your own base class which a large number of classes inherit from, to put your "universal" methods in.
Use traits which enable "horizontal code re-use", essentially by "compiler-assisted copy-and-paste".
You have to use the trait in each class where you want to "paste" its contents, but they will then be inherited from there, so you can have a handful of unrelated "base classes" all sharing a set of methods "pasted" from the same trait.
On the other hand, you might want to create a sub-class which takes an existing class and adds some methods using a trait.
More complex cases would require you to patch the source code of classes themselves. For instance, using a custom autoloader and https://github.com/nikic/php-parser to parse and manipulate class definitions before they are compiled. For instance, this just-for-fun sweary library installs as a Composer plugin and loads classes via a stream wrapper which removes restrictions such as "final".
Why not use a trait?
Unfortunately I haven't heard of anything like what you need in PHP.
<?php
trait Obj
{
static function test() { return 42; }
}
class User
{
use Obj;
}
echo User::test(); //prints 42
Hope this helps.
So I have a situation in an application where there is a CONSOLE app and WEB app.
Now if one knows Yii2 then he knows. There is
yiisoft/yii2/base/ErrorHandler.php
which is extended by
yiisoft/yii2/web/ErrorHandler.php
( FOR WEB in main.php config )
and
yiisoft/yii2/console/ErrorHandler.php ( FOR CONSOLE in main.php config )
Now here I want to override handleException function from yiisoft/yii2/base/ErrorHandler.php. Both ErrorHandler ( web and console ) do not override this method. This method is only in BaseErrorHandler.
So right now, I am extending both ErrorHandler from WEB and CONSOLE.
So I do have to make same changes in two different files/classes. For it to work.
What if I just want to extend BaseErrorHandler and do changes in new class ( ONLY ONE class ) there and make it available in both classes which extends base class.
You can not have a class extending two classes. You can achieve what you want however through the use of Traits. Traits by definition from the guide here is:
"a mechanism for code reuse in single inheritance languages
such as PHP. A Trait is intended to reduce some limitations of single
inheritance by enabling a developer to reuse sets of methods freely in
several independent classes living in different class hierarchies."
Practically what you need to do is create a trait containing the desired function with the desired behavior. Example:
trait handleExceptionMyWay {
public function handleException($exception) {
//Put here the desired functionality. Example:
return "Hello";
}
}
And then in each of your classes you should add the statement use handleExceptionMyWay; as such
class MyWebErrorHandler extends yii\web\ErrorHandler {
use handleExceptionMyWay;
}
This way the function that is defined in the trait is going to be used and not the original function from base\ErrorHandler
My whole project is basically divided into two parts:
core
helper classes
User creates his custom classes and uses methods from helper classes in there like:
\Project\System\Helpers\Class::foo();
So every public method in each helper class is declared as static. I've came up with an idea to change this, make all user custom classes inherit one special class:
class SingleBeingInheritedClass {
public function helper($class)
{
return new \Project\System\Helpers\$class; // it's just to show the idea
}
}
so that instead of calling static function, user could write:
$this->helper('class')->foo();
The problem is I use some of these helper classes inside a couple of core classes. And I don't want core classes to inherit anything related to helpers.
In these core classes I also don't want to make the code longer and initialize objects in every method using these helpers.
How should I handle this? Or maybe static methods aren't that bad here?
You wrote:
I also don't want to make the code longer and initialize objects in
every method using these helpers.
I you would like to avoid instantiating objects, then you shall stick to static methods. In my projects I use static methods for helpers, for the exact same reason.
These helper classes are then used as 'function libraries'. In this case, class is more like a namespace for the helper functions, not something which gets instantiated.
I'm building a small framework that I can use for repeated mundane stuff on future small projects.
I'm stuck on the best way to access libraries from inside a controller. I originally implemented a system similar to CodeIgniter's whereby my main controller class is basically a super object and loads all the classes into class variables which are then accessed by extending the controller and doing like $this->class->method()
I find that a little ugly, though. So I thought of just loading each class individually on a per-use basis in each controller method.
What's the best (cleanest) way of doing this?
To only ever have one instance of each class, you could create a simple service container.
class ServiceContainer
{
protected $services;
public function get($className)
{
if (!array_key_exists($className, $this->services)) {
$this->services[$className] = new $className;
}
return $this->services[$className]
}
}
Then create one ServiceContainer instance per application. Inject the container into all of your controllers and use
public function someAction()
{
$this->container->get('Mailer')->send($email_data);
}
Simple example, and obviously needs a lot of work to make useable (for instance autoloading needed and handling of file paths for ease of use, or easier way to add services without getting them, etc).
I dont like the way CodeIgniter does it. Its never seemed right to me. I favor an auto loading class pushed onto the spl_autoload stack. And then just calling the class as normal like:
$class = new SomeClass();
PHP provides autoload functionality with SPL and spl_autoload (and related functions). You can register a custom autoloader for your library code.
For the shared functionality handled by your application, have you considered the Front Controller design pattern?
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.