I'm trying to find a way to implement an Interface only when this Interface is available.
The Interface in question is
PrestaShop\PrestaShop\Core\Module\WidgetInterface
From Prestashop. It's used in a module.
The thing is, in order to be compatible with multiple version of Prestashop, the code must handle the case where WidgetInterface does not exists.
I was thinking in testing the existence of the interface and import it after, like this:
if (interface_exists('PrestaShop\PrestaShop\Core\Module\WidgetInterface')) {
use PrestaShop\PrestaShop\Core\Module\WidgetInterface
} else {
interface WidgetInterface {}
}
But of course, it's not possible to use use inside a if statement.
I then tried to do some try/catch, but that's the same issue (too bad it's not Python).
How can I do to implements WidgetInterface only when available?
You can't implement an interface dynamically, like you say, but you can write your own interface and only require it if the other does not exist.
Ie: your interface would be something like widget_interface.php, or whatever you want to call it, as long as it's not PSR-0/4 compliant, or autoloaded in whatever way you normally do.
<?php
namespace PrestaShop\PrestaShop\Core\Module;
/**
* This is the replacement interface, using the same namespace as the Prestashop one
*/
interface WidgetInterface
{
}
Then, in your class, you can do the following:
<?php
namespace App;
if (!interface_exists('\PrestaShop\PrestaShop\Core\Module\WidgetInterface')) {
require __DIR__ . '/path/to/widget_interface.php';
}
class WhateverClass implements \PrestaShop\PrestaShop\Core\Module\WidgetInterface
{
}
Your replacement interface will only be loaded if the Prestashop one doesn't exist.
True, you can't put use inside an if block, but use merely sets up an alias for the class. It doesn't attempt to load the class. So it can safely be outside the if block.
And you can define the class or interface itself inside an if.
This is how Symfony dealt with this exact issue, inheriting from an interface that may not exist:
namespace Symfony\Contracts\EventDispatcher;
use Psr\EventDispatcher\EventDispatcherInterface as PsrEventDispatcherInterface;
if (interface_exists(PsrEventDispatcherInterface::class)) {
interface EventDispatcherInterface extends PsrEventDispatcherInterface
{
public function dispatch($event);
}
} else {
interface EventDispatcherInterface
{
public function dispatch($event);
}
}
Personally, to keep things clean and contained in one spot, I would define your own interface like this that inherits from the PrestaShop interface if available or else provides its own implementation, and then have your class inherit from that.
Related
I have an abstract question for you.
Question:
How can a subclass that extends an abstract class register itself to the abstract class or another class?
Problem:
Guess we have a module master named ModuleMaster and maybe someone else writes another modules to handle a specific problem without modifying the master class and named it ModuleA. For that reason we want to implement a dynamic loading of problem solutions.
My idea:
File: Extensions.php:
namespace Project\Extensions;
class Extensions
{
public function getLoadedModules()
{
var_dump(ModuleMaster::LOADED_MODULES);
}
}
File: Modules\ModuleMaster.php:
namespace Project\Extensions\Modules;
abtract class ModuleMaster
{
public const LOADED_MODULES = array();
}
File: Modules\ModuleA.php:
namespace Project\Extensions\Modules;
class ModuleA extends ModuleMaster
{
}
I hope you understand what I mean and can help with that abstract problem.
This is very strange to use. It's probably a better design to have an external registry for your module. But I think you're asking for this:
File: Extensions.php:
namespace Project\Extensions;
use \Project\Extensions\Modules\ModuleMaster;
class Extensions
{
public function getLoadedModules()
{
var_dump(ModuleMaster::getLoadedModules());
}
}
File: Modules\ModuleMaster.php:
namespace Project\Extensions\Modules;
abstract class ModuleMaster
{
public static function getLoadedModules() {
$parent = self::class;
return array_values(array_filter(\get_declared_classes(), function ($class) use ($parent) {
return in_array($parent, class_parents($class));
}));
}
}
File: Modules\ModuleA.php:
namespace Project\Extensions\Modules;
use \Project\Extensions\Modules\ModuleMaster;
class ModuleA extends ModuleMaster
{
}
Example use:
$e = new \Project\Extensions\Extensions;
$e->getLoadedModules();
Example result:
array(1) {
[0]=>
string(34) "Project\Extensions\Modules\ModuleA"
}
Please note that the code only works if all your class files are included into the context before running getLoadedModules(). PHP won't know your class exists if it is not already loaded into the context.
You seem to be trying to create a capability in the parent class which is not required or inappropriate in the child class. This is the opposite of inheritance and hence an anti-pattern. Further, even though it might be considered as an extension of reflection, you are trying to put runtime data in a class - that's not what classes are for.
You've also not explained in any way that I can understand why you want to do this.
I suspect you really want to implement a factory, strategy or a registry object.
I have a question about using Trait and Interfaces in PHP.
A trait with foobar function
<?php
trait FoobarTrait
{
protected $foobar;
public function setFoobar($foobar)
{
$this->foobar = $foobar
}
public function getFoobar()
{
return $this->foobar;
}
}
The specific Interface to specify how to use Trait
<?php
interface FoobarInterface
{
public function setFoobar($foobar);
public function getFoobar();
}
I want use foobar feature in a class. What is the best way ?
It is necessary to implements with an interface and specify trait or it is an induced behavior ?
<?php
class FoobarClass implements FoobarInterface
{
use FoobarTrait;
}
Or this
<?php
class FoobarClass
{
use FoobarTrait;
}
Thank's for your reply and debate ;)
As it was correctly stated in the comments by #Federkun, "it depends". In my opinion mostly on how are you about to use your FoobarClass.
If it's an implementation of some kind of service that can have multiple implementations depending on external conditions (consider file system or S3 for handling user uploads, as an example), I would use FooBarInterface as I can then type-hint it in other places using the service.
If you wish to just avoid repeating yourself, you could use a trait and no interfaces. Or even a base abstract class AbstractFooBar { ... } to encapsulate the repeating code.
If you only have one implementation for getting and setting $fooBar - just put it all in the same class :)
Can anyone tell me if it's possible to override a use statement?
My example is having an MVC setup where there is core code with the ability to override each Controller / Model with a custom version that extends the core version.
The issue I face is that my core controller has a use statement telling it to use the core model, so if I extend the model, I'm not sure how to tell it to use the custom model rather than the core one
I could obviously update the core controller use statement to point to the custom one, but the core code is shared so the custom version may not exist on other sites that use this core core
Use statements are obviously file level so I'm guessing it's not possible, but I'm hoping there's either something I don't know about or maybe a workaround
Example
Core controller
namespace Core;
use Core\Model\Example as ExampleModel;
class ExampleController {
public function output() {
$model = new ExampleModel;
$model->test();
}
}
Core Model
namespace Core;
class ExampleModel() {
public function test() {
echo 'This is the core test';
}
}
Custom Controller
namespace Custom;
use Custom\Controller\Example as Base,
Custom\Model\Example as ExampleModel;
class ExampleController extends Base {
//Inherits the output() method
}
Custom Model
namespace Custom;
use Core\Model\Example as Base;
class ExampleModel extends Base {
public function test() {
echo 'This is the custom test';
}
}
So given this example, is it possible for me to create an instance of the custom controller which uses the custom model to output 'This is the custom test', without modifying the core code at all?
Hopefully what I'm asking makes sense
Thanks
I'm not quite sure I understand your question, but the answer should be self-evident: If your custom model extends from the core model, you can simply extend another class from that custom class
If you are writing code, that depends on a child of the core class being present, then that child class becomes a vital part of your project. If you can't change the core itself, add that class as a dependency. It's as simple as that.
Adding a second layer of inheritance needn't worry you, it's perfectly common to do so. Something like this is perfectly predictable, and reliable:
namespace Core;
class Model
{
public function coreTest()
{
return 'from the core';
}
}
namespace Custom;
use Core\Model;
class CustomModel extends Model
{
public function customTest()
{
return 'from the custom model';
}
}
//finally
namespace Project;
use Custom\CustomModel;
class ProjectModel extends CustomModel
{
public function test()
{
return array(
$this->coreTest(),
$this->customTest(),
'From the project'
);
}
}
$test = new ProjectModel();
echo implode(PHP_EOL, $test->test());
If, however you want a given class to extend from another class, based on whether or not that class exists, you are looking for conditional imports.
A simple use statement is evaluated at compile-time, so there's no way you can use an if check to switch between which class you extend from.
There is, however a hacky work-around, but I wouldn't rely on it. Check if the given class exists (without autoloading), and set an alias to the class that does.
if (!class_exists('\\Custom\\Model', false))
class_alias('\\Core\\Model', 'Base');
else
class_alias('\\Custom\\Model', 'Base');
class CustomModel extends Base
{}
But really: don't go down this route. Sure your code will work, but if you then rely on a method being available, that was defined in the custom class, but that class was missing, then your code will fail... horribly.
Details on conditional imports:
Why use class alisases?
I have seen some similar questions but I have yet to find a good solution for this from the interface all the way to the controller.
My Problem:
I have a few different kinds of applications that will require restarts, each has its own logic for restarting the application(SSH,API calls, etc.). I have set up an interface because although different logic, they all will need some similar functions. I have also created 3 classes, one for each app that implements that interface. where I am having issues is understanding the best way to keep the logic as abstracted from the controller as possible.
Some Questions:
Should I also be creating an Abstract class?
Should this be one controller that handles all types and chooses the correct one?
do I simply inject the different classes into the controller?
Code:
RestartInterface.php
<?php namespace Application\Service\Restart;
interface RestartInterface {
public function start();
public function stop();
public function restart();
}
example of implementing class:
<?php namespace Application\Service\Restart\AppOne;
use Application\Service\Restart\RestartInterface;
class AppOneRestart implements RestartInterface {
public function start() {
}
public function stop() {
}
public function restart() {
}
}
How could I use a service provider to keep this as modular as possible?
What is the best practice in this situation, I would like to be able to use many or as little restart implementations as I want.
thanks!
An abstract class is a way to create a base class you don't need your developers instantiating directly because, usually, there is still missing code from it, like, methods were not fully implemented. So you create an abstract which implements the common methods of your concrete restart classes
abstract class Restart {
public function restart() {
}
}
And then you implement one by one of those classes extending your abstract and creating the missing methods:
class AppOneRestart extends Restart implements RestartInterface {
public function start() {
}
public function stop() {
}
}
Option 1
If your whole application can use a single implementation of it and you just need the ability to swap from one to another, because your business somehow changed, a simple binding will do the trick:
App::bind('RestartInterface', 'AppOneRestart');
Option 2
If during a request you might need one or another, you probably will need to implement the Factory pattern: http://en.wikipedia.org/wiki/Factory_method_pattern, so you inject the factory in your controller:
class RestartApiController extends Controller {
public function __construct(RestartFactory $factory)
{
$this->restart = $factory->make('api');
}
}
I am creating a reporting library in PHP and developed an abstract class named ReportView. This will provide the basic functionality of a report like Generating header and footer, create parameter form.
There will be another function named generate_report in this class. Currently it is empty in abstract class as at this level we do not know the contents of report. Further it includes a render function which calls this generate_report function and sends output to browser.
So I need whenever a child class inherits from ReportView it must implement
the generate_report method otherwise PHP must give error. Is there any keyword or method through which we can enforce implemetation of a specific function.
Do the following:
abstract class ReportView {
abstract protected function generate_report();
// snip ...
}
class Report extends ReportView {
protected function generate_report() { /* snip */ }
}
Any class that extends ReportView and is not abstract must implement generate_report (and any other abstract function in its super classes for that matter).
Sounds like you’d be better off creating an interface, which would enforce you to define those methods in classes that then implement this interface.
<?php
interface ReportInterface {
public function generate();
}
class MyReportClass implements ReportInterface {
}
Instantiating MyReportClass here will throw a fatal error, telling you generate() has not been implemented.
Edit: You can also create abstract classes that implement this interface. You can have your abstract class contain any methods all extending classes need, and have your interface define any methods you need to be defined by extending classes.
You need to declare the method as abstract as well (and don't give it a method body), otherwise the derived classes will not be forced to implement it.
Alternatively, you could implement the method but have it just throw an Exception (not sure why you would want to do this).
Lastly, if all the methods in your base class are "abstract" (do not have bodies) then you can make the class into an Interface instead.