interface declaration in PHP - why do declarations get mixed? - php

I'm tring to declare interfaces for my classes like this:
namespace Helpers\Interfaces {
interface Cache {
public static function getInstance($profile = null);
}
}
And then I apply them like this:
namespace Helpers {
class Cache implements Interfaces\Cache {
public static function getInstance($profile = null) {
/* ... */
}
}
}
So far, so good (apparently, at least). The problem I have is NetBeans gives me an error stating my class is not abstract and doesn't implement a certain method.
The method belongs to an object I created to gather the configuration parameters needed to operate certain methods without providing specific configuration options depending on the object (like host, port, API key, etc.).
This method is, in this example, called as \Configuration\Helpers\Cache::getConfiguration($profile);
The conflicting declaration comes from this interface:
namespace Configuration\Helpers\Interfaces {
interface Cache {
public static function getConfiguration($profile = null);
}
}
Which is applied as follows:
namespace Configuration\Helpers {
class Cache implements Interfaces\Cache {
public static function getConfiguration($profile = null) {
/* ... */
}
}
}
It's effectively mixing the interfaces, although they're namespaced!
Something I would like to note is both the interface and the class declaration implementing such interface are always in the same file, one file per object.
PHP version is 7.0.13 on NetBeans 8.2.
What am I doing wrong?

Your interfaces and classes are in different namespaces. You may need to add a use statement to your class. For example you can add: use Helpers\Interfaces as Interfaces. This line can go above the class definition: class Cache implements Interfaces\Cache.
See also: http://php.net/manual/en/language.namespaces.definitionmultiple.php

Related

Implements Interface only if exists?

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.

PHP OOP abstract classes subclass registration

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.

Namespaces interfering with Classes in PHP - Best Practices? [duplicate]

I am trying the following :
//file1.
namespace foo;
class mine {
public function mine() {
echo "Does not work!!";
}
}
//file2.
use foo/mine;
include "foo/mine.php";
$obj = new mine();
the above scenario is not working. No errors including the file -- constructor does not get called.
However when i use __constructor(), everything works fine. I am using php v5.4
From php manual:
For backwards compatibility, if PHP 5 cannot find a __construct()
function for a given class, and the class did not inherit one from a
parent class, it will search for the old-style constructor function,
by the name of the class. Effectively, it means that the only case
that would have compatibility issues is if the class had a method
named __construct() which was used for different semantics.
As of PHP 5.3.3, methods with the same name as the last element of a
namespaced class name will no longer be treated as constructor. This
change doesn't affect non-namespaced classes.
You can use the name of the class as constructor (unless the class is namespaced) because PHP5 keeps this for backwards compatibility with PHP4, but this is not recomended because it is the old way and may be removed in newer versions of php. So unless you are writting something that needs for some reason to be PHP4 compatible use __construct().
Below are 2 different possible solutions to the namespace\constructor problem
//parentclass.php
class parentclass
{
public function __construct()
{
//by default, strip the namespace from class name
//then attempt to call the constructor
call_user_func_array([$this,end(explode("\\",get_class($this)))],func_get_args());
}
}
//foo/bar.php
namespace foo;
class bar extends \parentclass
{
public function bar($qaz,$wsx)
{
//...
}
}
$abc = new foo\bar(1,2);
and
//parentclass.php
class parentclass
{
public function __construct()
{
//by default, replace the namespace separator (\) with an underscore (_)
//then attempt to call the constructor
call_user_func_array([$this,preg_replace("/\\/","_",get_class($this))],func_get_args());
}
}
//foo/bar.php
namespace foo;
class bar extends \parentclass
{
public function foo_bar($qaz,$wsx)
{
//...
}
}
$abc = new foo\bar(1,2);

Use Trait, Interfaces or both?

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 :)

Hide Restler method from swagger-ui

Using Restler 3.0.0-RC6, which internally packages swagger-ui, I have an API method defined like so:
<?php
namespace v1:
class PostgreSQL {
public function fetchArray($sql, $args = null) {
And then all of my classes that I include via Restler's addAPIClass extend that PostgreSQL class. That means when swagger runs, every single API shows a fetchArray function. I'd like to have that method not appear in the swagger documentation as it's not really part of the API. Other 'things' on the website also use the class though so I can't change the modifier from public.
What's the proper syntax to hide that method from swagger-ui's webpage?
There are two ways to achieve this,
One is to mark the fetchArray method as private with #access private comment. This will remove fetchArray from all api urls while keeping the fetchArray still accessible for PHP
Problem in your case is that you don't want to modify the PostgreSQL as its part of a framework that is maintained by composer. Instead of directly extending it from the base class use an intermediary class which adds the comment and then extend that class as shown below
class Base {
public function fetchArray(){
return array();
}
}
class Intermediary extends Base {
/**
* #access private
*/
public function fetchArray(){
return array();
}
}
class MyApi extends Intermediary { //instead of extends Base
//other api methods here
//see in the explorer to note that fetchArray is no longer listed
}
Another way is to just exclude it on Explorer with
use Luracast\Restler\Explorer;
Explorer::$excludedPaths = array('myapi/fetcharray','another/fetcharray');
You should not extend your API layer class from a data layer class. Just use the data layer class.
class DataLayer
{
public function fetchArray()
{
return array();
}
}
class ApiLayer
{
private $dl;
function __construct()
{
$this->dl = new DataLayer();
}
public function getAll()
{
return $this->dl->fetchArray();
}
}

Categories