How to override methods in Dispatch.php - php

I'm hard coding the $connection and $queue in over 10 files so I'm trying to clean that up. My first thought is to create some helpers that I can access in all of these files. However, I don't need those methods/variable available throughout my entire app. Instead, it would make most sense to place them in the ShouldQueue class. Any thoughts on the proper way to do this?
namespace App\Listeners\User;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Log;
class CreateJenzUser implements ShouldQueue
{
use InteractsWithQueue;
public $connection = 'sqs_high';
public $queue = 'portal_high.fifo';
//Would rather use
public $connection = $highConnection;
public function handle(UserBeingCreated $event)
{
}
}
EDIT
It turns out Laravel is creating a new instance of CreateJenzUser without the constructor.
vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php - line 479
/**
* Create the listener and job for a queued listener.
*
* #param string $class
* #param string $method
* #param array $arguments
* #return array
*/
protected function createListenerAndJob($class, $method, $arguments)
{
$listener = (new ReflectionClass($class))->newInstanceWithoutConstructor();
return [$listener, $this->propagateListenerOptions(
$listener, new CallQueuedListener($class, $method, $arguments)
)];
}
Just need to figure out how to override this method.

I would make a parent abstract class and extend it from all the classes that needs to use the queue. You can specify all the method that you must implement as abstract methods in the parent class so you do not need to implement the ShouldQueue interface.
So, the parent class will look like
abstract class Queue
{
use InteractsWithQueue;
protected $connection = 'sqs_high';
protected $queue = 'portal_high.fifo';
// list here all the methods in your ShouldQueue interface
abstract protected function handle(UserBeingCreated $event);
}
Then the child class:
class CreateJenzUser extends Queue
{
protected function handle(UserBeingCreated $event)
{
// your code here
}
}
Update
If you need to keep the interface (for type hint check for example) you can extend and implement in the same time. So, the child class in this case will look like:
class CreateJenzUser extends Queue implements ShouldQueue
{
protected function handle(UserBeingCreated $event)
{
// your code here
}
}
The Queue class may not need to be abstract in this case. However, that depends on how you want to design. If you have some methods that you want to call from the parent but define in the child you can still keep it as an abstract class.

It sounds like that all those classes share code, that should be refactored. Probably the best option would be to extract class and then pass it as a dependency in the constructors of classes, which need that behavior.
You should also consider the fact, that trait is basically interpretator assisted copy-paste. You are just using a language structure to hide that code duplication.
P.S.
Don't use extends to fix this. The "extends" keyword should be read as "is a special subtype of". And user is not a special type of queue ... frankly, some could see it as an insult.

Related

Laravel ShouldQueue How Does It Work

I know how to use ShouldQueue my question is about why does it work the way it does.
I need to edit how my new Job is stored in the database, and therefore am digging through Laravel's internals.
The job I want to edit is launched from the following event listener:
<?php
namespace App\Listeners;
use App\Events\NewMail;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Jobs\SendEmail;
use Carbon\Carbon;
class NewMailListener implements ShouldQueue
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param NewMail $event
* #return void
*/
public function handle(NewMail $event)
{
$addressee = $event->user->name;
$address = $event->user->email;
$type = "NewMail";
$job = (new SendEmail($type,$addressee,$address))->delay(Carbon::now()->addMinutes(10));
dispatch($job);
}
}
What I don't understand is how the ShouldQueue magic works, because in the source code it appears to do nothing.
<?php
namespace Illuminate\Contracts\Queue;
interface ShouldQueue
{
//
}
I understand it is a contract but it's not defining anything... so what it is doing exactly? Is there some auto-loading happening from the namespace?
I wasn't sure what an interface was exactly, so I looked at this: PHP Docs: Interfaces and came away with the impression that even if it is for decoupling, and interface should be defining something, which I don't see in ShouldQueue.
The top comment on that PHP docs page says this:
An INTERFACE is provided so you can describe a set of functions and
then hide the final implementation of those functions in an
implementing class. This allows you to change the IMPLEMENTATION of
those functions without changing how you use it.
But where is this description of functions here?
PS - I know this interface/contract is being used to queue the event listener itself, not the job that I want to edit. But I'm hoping understanding how the queue interacts with the event listener will better inform me as to how it works for the jobs.
Internally Laravel checks if Job or Mailable or Notification etc implements ShouldQueue interface. For example:
if ($job instanceof ShouldQueue) {
https://github.com/laravel/framework/blob/5.5/src/Illuminate/Console/Scheduling/Schedule.php#L86

Resolving abstract class' dependencies via dependency injection in Laravel

I encountered this issue using the repository pattern. Currently I use an interface, and a custom class to achieve it, then type-hint it into the controller's construct and because of Laravel, it will solve the repositories' dependencies automatically and recursively.
I also do this in a service provider:
$this->app->bind(path/to/repoInterface,path/to/implementationClass)
However, because of the way I coded these repositories, in order to avoid code duplication, I created an abstract class that has a common method to all these repositories. This class is as follows:
abstract class CommonRepo{
public function __construct(SomeModelClass model){}
public function commonMethod(){//Code here}
And my repositories have the following structure:
public class ExampleRepository extends CommonRepo implements ExampleRepositoryI{
public function __construct(){
parent::__construct();
}
}
Laravel doesn't like this, so its giving this error:
Argument 1 passed to path/to/repo/CommonRepo::__construct() must be an instance of path/to/model/SomeModelClass, none given, called in...
So, obviously is not resolving the dependency of the class CommonRepo, but it does resolve the dependencies on the normal repositories.
I'd like, if it's possible, to use type-hinting (the Laravel way) without having to do anything related to the new operator
How can I, then, resolve that class's dependencies ?
PD: Using Laravel 5.2
Parent constructor is called like normal function without touching dependency resolver so you should do one of two possibilities:
public class ExampleRepository extends CommonRepo implements ExampleRepositoryI
{
public function __construct(SomeModelClass $model){
parent::__construct($model);
}
}
or
public class ExampleRepository extends CommonRepo implements ExampleRepositoryI
{
public function __construct(){
parent::__construct(App::make(SomeModelClass::class));
}
}
nice question. I did some tinkering, though I don't know if this is what you're looking for. But you can dynamically create an instance of Eloquent model required by your repository class.
Let's say you have your User model class stored in app\Models\User.php:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
//
}
You then create a base abstract class for all of your repository classes: app\Repositories\BaseRepository.php. This is where you place all common functionalities for your repository classes. But rather than injecting the Eloquent instance through the constructor, you may add a method named getModel() to dynamically create an instance of Eloquent model for your repository.
<?php
namespace App\Repositories;
use ReflectionClass;
use RuntimeException;
use Illuminate\Support\Str;
abstract class BaseRepository
{
protected $modelNamespace = 'App\\Models\\';
public function getById($id)
{
return $this->getModel()->find($id);
}
public function getModel()
{
$repositoryClassName = (new ReflectionClass($this))->getShortName();
$modelRepositoryClassName = $this->modelNamespace . Str::replaceLast('Repository', '', $repositoryClassName);
if (! class_exists($modelRepositoryClassName)) {
throw new RuntimeException("Class {$modelRepositoryClassName} does not exists.");
}
return new $modelRepositoryClassName;
}
}
Now let's say you want to create a repository for your User model, and this user's repository must implement the following interface: app\Repositories\UserRepositoryInterface.php
<?php
namespace App\Repositories;
interface UserRepositoryInterface
{
public function getByEmail($email);
}
You create app\Repositories\UserRepository.php class and simply extend it from the BaseRepository class. Also don't forget to implement all specific implementations defined on UserRepositoryInterface.
<?php
namespace App\Repositories;
use App\Repositories\BaseRepository;
use App\Repositories\UserRepositoryInterface;
class UserRepository extends BaseRepository implements UserRepositoryInterface
{
public function getByEmail($email)
{
return $this->getModel()->where('email', $email)->firstOrFail();
}
}
This way you can bind the UserRepositoryInterface to it's implementation like so:
$this->app->bind(\App\Repositories\UserRepositoryInterface::class, \App\Repositories\UserRepository::class);
Finally you can freely inject the UserRepositoryInterface to a controller's constructor or methods. You can also resolve it via service container like this:
$userRepository = App::make(App\Repositories\UserRepositoryInterface::class);
$userRepository->getByEmail('john#example.com');
Of course there's a catch to this approach. The repository class should be started with the associated model, so the InvoiceRepository.php is dedicated for Invoice.php model class.
Hope this help!
This might help. You can listen in for when an object resolves and set attributes.
$this->app->resolving(CommonRepo::class, function ($object, $app) {
// Called when container resolves object of any type...
$object->commonObject = app(CommonObject::class);
});
Docs: https://laravel.com/docs/5.4/container#container-events

Dispatch controller zf2 event manager

I have a base controller named MyController
I extend my Controller from MyController instead of AbstractActionController
What's wrong with this code ?
It doesn't work :
$sharedEventManager->attach('MyController', 'dispatch', function ($e) {
$controller = $e->getTarget();
},100) ;
but this does :
$sharedEventManager->attach('Zend\Mvc\Controller\AbstractActionController', 'dispatch', function ($e) {
$controller = $e->getTarget();
},100) ;
The first parameter of the SharedEventManager::attach() is the identity of the event manager to target. This identity is dynamically assigned for any class that is event capable (implements Zend\EventManager\EventManagerAwareInterface) or has otherwise had it's identity set via $eventManager->setIdentity().
The question refers to the \Zend\Mvc\Controller\AbstractActionController; this itself is an identity given to any controller that extends \Zend\Mvc\AbstractActionController (among others), allowing for just one id to attach() to target all controllers.
To target just one controller (which is perfectly valid, there are many use cases), you can do so in two ways:
via the SharedEventManager, external to the controller class (as you have been doing)
directly fetching said controller's event manager and handling the events within the controller class.
via SharedEventManager
Use the fully qualified class name as this is is added as an identity to the event manager
$sharedEventManager->attach(
'MyModule\Controller\FooController', 'dispatch', function($e){
// do some work
});
Within controller
I modify the normal attachDefaultListeners() method (which is called automatically), this is where you can attach events directly.
namespace MyModule\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\EventManager\EventInterface;
class FooController extends AbstractActionController
{
protected function attachDefaultListeners()
{
// make sure you attach the defaults!
parent::attachDefaultListeners();
// Now add your own listeners
$this->getEventManager()->attach('dispatch', array($this, 'doSomeWork'));
}
public function doSomeWork(EventInterface $event) {
// do some work
}
}
Why do you use your own base controller? there is no real benefit of doing that, unless you have rare edge case scenario.
Your base controller class is missing this part from AbstractController:
/**
* Set the event manager instance used by this context
*
* #param EventManagerInterface $events
* #return AbstractController
*/
public function setEventManager(EventManagerInterface $events)
{
$events->setIdentifiers(array(
'Zend\Stdlib\DispatchableInterface',
__CLASS__,
get_class($this),
$this->eventIdentifier,
substr(get_class($this), 0, strpos(get_class($this), '\\'))
));
$this->events = $events;
$this->attachDefaultListeners();
return $this;
}
See setIdentifiers call there? That is why second example works.
Also i suspect you might not actually trigger dispatch event in dispatch() method of your controller
As side note: you should never create classes without top level namespace. Eg all my classes use Xrks\ vendor namespace

Symfony2 - How to use __construct() in a Controller and access Securty.Context?

I am having some trouble with Symfony2. Namely in how to use the __construct() function. the Official Documentation is shockingly bad!
I want to be able to use the following:
public function __construct()
{
parent::__construct();
$user = $this->get('security.context')->getToken()->getUser();
}
How ever I get the following error:
Fatal error: Cannot call constructor in /Sites/src/DEMO/DemoBundle/Controller/Frontend/HomeController.php on line 11
Line 11 is "parent::__construct();"
I removed it and got the following, new error
Fatal error: Call to a member function get() on a non-object in /Sites/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php on line 242
I think I might need to set up the ContainerInterface DIC, but I have no idea how to do this (I tried and failed, miserably)
Any ideas folks?
Update - Tried changing to extend ContainerAware and got this error:
Fatal error: Class DEMO\DemoBundle\Controller\Frontend\HomeController cannot extend from interface Symfony\Component\DependencyInjection\ContainerAwareInterface in /Sites/src/DEMO/DemoBundle/Controller/Frontend/HomeController.php on line 43
Using the following code in the controller:
<?php
namespace DEMO\DemoBundle\Controller\Frontend;
use Symfony\Component\DependencyInjection\ContainerAware;
class HomeController extends ContainerAwareInterface
{
protected $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
I'm assuming you are extending the default Symfony controller? If so, a look at the code will reveal the answer:
namespace Symfony\Bundle\FrameworkBundle\Controller;
use Symfony\Component\DependencyInjection\ContainerAware;
class Controller extends ContainerAware
{
Notice that there is no Controller::__construct defined so using parent::__construct will not get you anywhere. If we look at ContainerAware:
namespace Symfony\Component\DependencyInjection;
class ContainerAware implements ContainerAwareInterface
{
protected $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
}
Again, no constructor and the container is not available until setContainer is called. So override setContainer and put your logic there. Or else just make a stand alone controller that does not extend the base controller class and inject your dependencies directly into the constructor.
Update Aug 2017
Still getting a few hits on this. If you really want to execute something before each controller then use a kernel controller listener. If all you need is the user then of course use getUser(). And please don't override setContainer(). In some cases it would work but it would just convolute your code.
I also frequently want an instance of the current User in most of my controllers. I find it is easiest to just do something like this:
class SomeController extends Controller
{
protected $user;
public function getUser()
{
if ($this->user === null) {
$this->user = $this->get('security.context')->getToken()->getUser();
}
return $this->user;
}
}
However, this is an overly simplistic example case. If you want to do more work before a Controller action is started, I suggest you define your Controller as a Service.
Also take a look at this article: Moving Away from the Base Controller
I have to retrieve the 'facade' manager for my rest api's resource. Not using the constructor and using a private function seems the easiest and simplest for me.
/**
* Class ExchangesController
* #RouteResource("Exchange")
*/
class ExchangesController extends Controller
{
/**
* Get exchange manager
* #return ExchangeManager
*/
protected function getExchangeManager()
{
return $this->get('exchange_manager');
}
/**
* #ApiDoc(
* description="Retrieve all exchanges",
* statusCodes={
* 200="Successful"
* }
* )
*/
public function cgetAction()
{
return $this->getExchangeManager()->findAll();
}
PS It's ok for me to use private/protected functions in my controller as long as it contains zero conditionals
You cannot call getUser() or get() for services in controller constructors. If you remember that, you will save lots of debugging time.
I know the question is very old, but I didn't found an answer until now. So I'll share it.
The goal here, is to execute a code everytime a action in our controller is called.
The __construct method doesn't work, because it's called before anything else, so you can't access the service container.
The trick is to overload each method automatically when they are called :
<?php
namespace AppBundle\DefaultController;
class DefaultController extends Controller {
private function method1Action() {
return $this->render('method1.html.twig');
}
private function method2Action() {
return $this->render('method2.html.twig');
}
public function __call($method, $args) {
$user = $this->get('security.tokenStorage')->getToken()->getUser();
// Do what you want with the User object or any service. This will be executed each time before one of those controller's actions are called.
return call_user_func_array(array($this, $method), $args);
}
}
Warning ! You have to define each method as a private method ! Or the __call magic method won't be called.
There are only two solutions to this problem:
Use a private method as pointed out by #Tjorriemorrie here. But this is a dirty method for purists. (I'm using this! :D );
Define the controller as a service, but this way you will lose all the shortcuts provided by Symfony\Bundle\FrameworkBundle\Controller\Controller. Here is the article that shows how to do this.
As told, personally, in my situation, I prefere a solution like this:
class MyController extends Controller
{
/** #var AwesomeDependency */
private $dependency;
public function anAction()
{
$result = $this->getDependency();
}
/**
* Returns your dependency.
*/
private function getDependency()
{
if (null === $this->dependency)
$this->dependency = $this->get('your.awesome.dependency');
return $this->dependency;
}
}
This is typically a class that I call MyManager where I put the code that I use in more than one action in the controller or that unusefully occupies lines (for example the code to create and populate forms, or other code to do heavy tasks or tasks that require a lot of code).
This way I mantain the code in the action clear in its purposes, without adding confusion.
Maybe the use of a property to store the dependency is an overoptimization, but... I like it :)
As i see, Controller extends ContainerAware, and if we take a look of ContainerAware it implements ContainerAwareInterface. So, ContainerAware must have declared the exact methods in it's interface. Add this line
public function __construct();
to the ContainerAwareInterface definition and it will be solved.

How to implmenet this mechanism using Abstract Class in PHP?

From the past two days i have been diving into the concepts of OOPS in PHP, and i found Abstract Class to be very useful concept and i wanted to implement it in my application. and here is why i want to implement it.
My Application Consist of Several Unstructured Pattern which uses several different classes without any hierarchies, due to this i have to use several repeated codes. i want to cut this all up and structure it properly, basically what i want to do is
Define a parent class which is not instantiable from outside.
Define all properties in this parent class so that i can re-use the same property for different child classes.
Define re-usable class methods and objects so that child class can use it without the need of defining it again and again (Inheritance).
Basically My Abstract class should be capable of inheriting the re-usable methods and properties and at the same time it should act as an Interface.
To demonstrate you clearly let me show you some sample codes which i have been using.
public $error = array(); //used to handle error mechanism and to hold the errors.
private $data = array(); //used with Accessor Methods (__set and __get)
private $validate; //holds Validate Object
private $dbh; //holds Database Object
public function __set($property, $value) {
if( in_array($property, $this->data)) {
return $this->data[$property] = $value;
} else {
return false;
}
}
public function __get($property) {
return 'Access Denied to Class Property [ '.$property.' ]';
}
Above codes are repeated for almost every class, this is the reason i want to define it once in a parent class and control the mechanism from there.
As i am still Novice to Many OOPs concept i am unable to understand how do i achieve what i want using Abstract Class. below is the sample code i tried using which ofcourse is wrong for declaring an abstract method.
abstract class Property {
protected $error = array();
protected $data = array();
protected $dbh;
protected $validate;
abstract protected function connectDB($dbhandle) {
return $this->dbh = $dbhandle;
}
abstract protected function setValObj($valObj) {
return $this->validate = $valObj;
}
public function __set($property, $value) {
}
public function __get($property) {
}
}
here is what i want to do.
When a child class is initiated it should be forced to define methods as declared in abstract class.
A Child class should only be able to call and pass the arguement but not extend an abstract method. the mechanism should be handled by parent class. this is what i tried to do in my code.
i know i am missing something, or might be i have not got the concept right, could somebody explain me what exactly should i be doing to achieve the same result.
1 . Define a parent class which is not instantiable from outside.
All abstract classes can not be instantiated, only extended. So this is what you already have:
abstract class Property {
On to the next:
2 . Define all properties in this parent class so that i can re-use the same property for different child classes.
Just write them into that abstract class (often called base class or abstract base class or template class as well). All classes extending from a base class, will have access to protected or public member methods and properties. If you make a variable or function private, it's only available to code in the base class.
So just define all you want to have in the base class to be shared amongst all extending classes and you only need to type it once.
3 . Define re-usable class methods and objects so that child class can use it without the need of calling it again and again (Inheritance).
This works automatically. As you extend from the base class, the public and protected class methods defined therein are automatically accessible through the extending class. You do not (but you can unless specified with final) need to add that function again to make it available. E.g. all public methods from the base class are automatically available publicly on all classes that extend from it.
Then you continue:
here is what i want to do.
1 . When a child class is initiated it should be forced to define methods as declared in abstract class.
You can do so by defining these needed methods as abstract. Abstract methods needs to be implemented by the extending class. However you can not put code into abstract methods in the base class. That's left there for the extending class.
2 . A Child class should only be able to call and pass the arguement but not extend an abstract method. the mechanism should be handled by parent class. this is what i tried to do in my code.
If you want to prevent a subclass to overwrite a function, declare it as final in your base class. Final methods can not be further extended.
But probably you want to do something that is technically not possible, e.g. prevent that a method can be extended while you require that is should be extended.
In your code you're using magic functions to access the properties / values. Those don't count in the sense that their name changes. So you loose the control of the inheritance for a bigger part of your class design.
However, you can implement array access to offer getter/setters. It's bound to a concrete interface and you then can disallow access through the base class and prevent extending of this area for classes that will extend from it.
Let me know if you would like to have some example code, probably SPL is new to you as well.
Provide variable inheritance via ArrayAccess
As you've been running into the problem that inheritance can not be easily used on the magic function __get() and __set() which are available, I had the idea to make that part of the access concrete that does not change (get, set) while it's still possible to name the property variable. An interface that is available with PHP that already does this is ArrayAccess. It was designed to give access to properties via the style we know from standard php arrays ([]) and it's normally used for that. But for this example it has the benefit to already provide an interface as well that fits the general need.
First a demonstration how such a class behaves in use:
# give birth to the object
$object = new PropertyClass; // one of your property classes
# get:
$value = $object['propertyA'];
# set:
$object['propertyA'] = 'new value';
# unset:
unset($object['propertyA']); // and gone ;)
# isset:
isset($object['propertyA']); // true / false
Okay, as this shows, this looks like an array, but is an object. The rest of $object works as known, so this is no limitation, but an addition.
As you can imagine already with this code, there must be a get and set routine as well for reading and setting the properties values like with __get() and __set(). Additionally there must be something for isset and unset, so four. This is the interface definition of ArrayAccess:
ArrayAccess {
/* Methods */
abstract public boolean offsetExists ( mixed $offset )
abstract public mixed offsetGet ( mixed $offset )
abstract public void offsetSet ( mixed $offset , mixed $value )
abstract public void offsetUnset ( mixed $offset )
}
You can extend from that in PHP by implementing the interface. That's not extends but implements. This works with every interface in PHP, but this interface is something special as well. It's provided by the SPL/PHP itself and in the moment a class of yours actually implement the functions, the functionality as described in the code above is automatically added to your class.
As those functions are available publicly, you could call them with their name as well naturally.
So actually this interface qualifies for a properties object as you want to build one and will give you an interface you can put your constraints on.
So the only question left is: How can this look like for your properties class?
Implementing ArrayAccess to a variable properties class
<?php
/**
* Property Object base class based on ArrayAccess
*/
abstract class PropertyObject implements ArrayAccess
{
/** Interface Methods */
/**
* implementing classes must return all names of their properties
* in form of an array.
*/
abstract protected function returnNames();
/** class */
/**
* value store
*
* #var array
*/
private $store = array();
/**
*
* By this design, properties can only contain A-Z and a-z.
*
* look like.
*
* #return bool
*/
private function isValidPropertyName($name) {
return ctype_alpha($name);
}
private function checkOffsetArgument($offset) {
if ($this->isValidPropertyName($offset)) return;
throw new InvalidArgumentException(sprintf('"%s" is not a valid property name.', $offset));
}
private function setNames(array $names) {
foreach($names as $name) {
$this->checkOffsetArgument($name);
}
$len = count($names);
$this->store = $len
? array_combine($names, array_fill(0, $len, null))
: array()
;
}
/**
* final constructor to obtain control
*/
final public function __construct() {
$this->setNames($this->returnNames());
}
/**
* ArrayAccess impl.
*
* #return bool
*/
public function offsetExists($offset) {
$this->checkOffsetArgument($offset);
return array_key_exists($offset, $this->store);
}
/**
* ArrayAccess impl.
*
* #return mixed
*/
public function offsetGet ($offset) {
$this->checkOffsetArgument($offset);
return $this->store[$offset];
}
/**
* ArrayAccess impl.
*/
public function offsetSet($offset, $value) {
$this->checkOffsetArgument($offset);
if (!$this->offsetExists($offset)) {
throw new InvalidArgumentException(sprintf('Property "%s" can not be set.', $offset));
}
$this->store[$offset] = $value;
}
/**
* ArrayAccess impl.
*/
public function offsetUnset($offset) {
$this->checkOffsetArgument($offset);
unset($this->store[$offset]);
}
}
/**
* I feel so concrete.
*/
class ConcreteType extends PropertyObject
{
protected function returnNames() {
return array('propertyA');
}
}
$obj = new ConcreteType;
var_dump($obj['propertyA']); # NULL, maybe you need other default values.
$obj['propertyA'] = 'hello';
var_dump($obj['propertyA']); # string(5) "hello"
var_dump(isset($obj['propertyA'])); # bool(true)
// this will trigger an exception
try {
$obj['XProperty'] = 'good night.';
} catch (Exception $e) {
var_dump($e->getMessage()); # string(36) "Property "XProperty" can not be set."
}
// the following might be unwanted but can be prevented in base class:
unset($obj['propertyA']);
var_dump(isset($obj['propertyA'])); # bool(false)
I think you need to implement mixin interface. According to my knowledge PHP does not support this natively. Some PHP frameworks (like Yii framework) implemented it by itself. I found one example here. But I am sure you will be able to find better examples.

Categories