I'm writing a PHP class similar to Java's Currency:
The class is designed so that there's never more than one Currency instance for any given currency. Therefore, there's no public constructor. You obtain a Currency instance using the getInstance methods.
It's fairly easy with PHP to keep a static array of instantiated objects, and perform a lookup in getInstance() to return an existing instance, or instantiate it if needed.
The problem comes with serialization. Even if I implement Serializable, I have no way to choose the instance I want to return in unserialize(), as the object is already instantiated at this point, and because in PHP you cannot override $this:
class Currency implements Serializable
{
public function getInstance()
{
// ...
}
public function serialize()
{
// ...
}
public function unserialize($data)
{
// At this point, the object is already instantiated,
// so I can't just return self::getInstance(),
// and can't override $this
}
}
Is there any technical solution to choose the instance to return upon unserialization?
-- edit --
This is the use case I'm trying to solve:
$euro = Currency::getInstance('EUR');
assert($euro === unserialize(serialize($euro));
I know that I can build a similar object with unserialize(), but I'm wondering if it's ever possible to get the same object.
td;dr; No, you can't do this natively in PHP, because unserialize() doesn't support the same readResolve() functionality as Java does.
In Java, on deserialization, a new instance of an object is created, its state is restored, then readResolve() is invoked on the class, if it exists. readResolve() takes the newly created deserialized object, then resolves it to another object (if needed), at which point the resolved object is what's returned from deserialization. The new instance that was originally created is left to be garbage collected if readResolve() returned a different object than the one that was supplied to it.
In PHP, there is no such hook within unserialize(). You can implement a workaround, however, define your own resolve method to emulate readResolve(), but you would be required to call it after unserialize().
class Currency implements Serializable {
private $currencyCode;
private static $instances = array();
private function __construct( $currencyCode) {
$this->currencyCode = $currencyCode;
}
public static function getInstance( $currencyCode) {
if( !isset( self::$instances[$currencyCode])) {
self::$instances[$currencyCode] = new Currency( $currencyCode);
}
return self::$instances[$currencyCode];
}
public function serialize() {
return serialize( $this->currencyCode);
}
public function unserialize( $data) {
$this->currencyCode = unserialize( $data);
}
public static function resolve( $obj) {
$new = self::getInstance( $obj->currencyCode);
if( $new !== $obj) {
unset( $obj);
}
return $new;
}
}
$euro = Currency::getInstance('EUR');
assert($euro === Currency::resolve( unserialize(serialize($euro))));
Of course, there is nothing stopping somebody from not calling Currency::resolve(), and you will then end up with more than one object for the given currency code.
Related
In the progress of writing a little framework for a web app I came along some difficulties in making classes communicate with each other.
Environment
I have an abstract class called LizardModule, that should be extended by all the single modules of the web-app. This class has a final protected function registerController(...), that creates a new Object of the type LizardController. This is, as it sounds, based on the idea of MVC. With the final protected function registerFunction(...), modules can register functions for every controller. Those are stored using addFunction(...) on the controller object. Here is what this looks like:
Example Module:
class ModuleOverview extends LizardModule {
protected function setup() {
$this->registerController(
'overview',
'App Overview'
);
$this->registerFunction(
'overview',
'myfunction',
'My Function',
array(&$this, 'theFunctionToCall')
);
}
public function theFunctionToCall() { ... Generate Content ... }
}
Module Class:
class LizardModule {
private $controllers = array();
final public function __construct() { $this->setup(); }
abstract protected function setup();
[...]
final protected function registerController($controllerSlug, $controllerName) {
if (array_key_exists($controllerSlug, $this->controllers))
return false;
$this->controllers[$controllerSlug] = new LizardController($controllerSlug, $controllerName);
}
final protected function registerFunction($controllerSlug, $functionSlug, $functionName, callable $function) {
if (!array_key_exists($controllerSlug, $this->controllers))
return false;
$this->controllers[$controllerSlug]->addFunction($functionSlug, $functionName, $function);
}
}
This results in a lot of objects of type LizardController in different places of the app. To make all of those objects accessable, I created a singleton class LizardRouter, that should hold a reference to all of those controller objects. Therefore, the controller-object registers itself with this singleton class:
Controller Class:
class LizardController {
[...]
private $functions = array();
public function __construct($slug, $name, $menu) {
$this->slug = $slug;
$this->name = $name;
$this->menu = $menu;
LizardRouter::registerController($this);
}
public function addFunction(...) { Tested, this works. }
public function getFunctions() {
return $this->functions;
}
}
Router Class:
final class LizardRouter {
[...]
public static function getControllers() {
return static::getInstance()->controllers;
}
public static function registerController(LizardController $controller) {
static::getInstance()->controllers[] = $controller;
}
}
The Problem
The whole thing works alright for the controllers. In my interface class, I can read out all controllers and print a menu containing their names. The problem is: Whenever I access the controllers functions-array (see controller class) through the controllers-array given by the routing class, I get an empty array. I asume that somewhere a reference is not working and I am passing the actual controller object, before my module-class was able to add the functions to the controllers functions-array. But I can't figure out where exactly the problem lies. Here is an example from my interface class showing the problem:
foreach (LizardRouter::getControllers() as $controller) {
// Allways returns an empty array, even though
// the module added functions to the controller.
$controller->getFunctions();
}
Since this is a very specific case, I guess it is unlikely, that anyone will ever stumble upon the same problem. Anyway; I found the reason for the problem:
Objects are by default passed as reference since PHP5. Variables are by default passed by value.
Arrays are handled like variables, so when I pass an array containing object-references, a new copy of this array is created and passed. Object references added to the array after it was passed are therefore only added to the original array.
The solution i chose was to create my own "array-class" for holding objects. It has nothing more than a private array object, a setter and a getter. Since this custom array class is an object, it is automatically passed by reference. Later I also added some functions to conveniently access the array - a good side-effect.
Is it a good idea to create objects that cannot be changed in PHP?
For example a date object which has setter methods, but they will always return a new instance of the object (with the modified date).
Would these objects be confusing to other people that use the class, because in PHP you usually expect the object to change?
Example
$obj = new Object(2);
$x = $obj->add(5); // 7
$y = $obj->add(2); // 4
Immutable objects don't have setter methods. Period.
Everyone will expect a setXyz() method to have a void return type (or return nothing in loosely typed languages). If you do add setter methods to your immutable object it will confuse the hell out of people and lead to ugly bugs.
In my opinion objects should be immutable for value objects. Other than that it does not have much benefits unless you're sharing your object across your whole application.
There is some wrong answers here, an immutable object can have setters. Here's some implementation of immutable objects in PHP.
Example #1.
class ImmutableValueObject
{
private $val1;
private $val2;
public function __construct($val1, $val2)
{
$this->val1 = $val1;
$this->val2 = $val2;
}
public function getVal1()
{
return $this->val1;
}
public function getVal2()
{
return $this->val2;
}
}
As you can see once instantiated you cannot changed any value.
Example 2: with setters:
class ImmutableValueObject
{
private $val1;
private $val2;
public function __construct($val1, $val2)
{
$this->val1 = $val1;
$this->val2 = $val2;
}
public function getVal1()
{
return $this->val1;
}
public function withVal1($val1)
{
$copy = clone $this;
$copy->val1 = $val1;
return $copy; // here's the trick: you return a new instance!
}
public function getVal2()
{
return $this->val2;
}
public function withVal2($val2)
{
$copy = clone $this;
$copy->val2 = $val2;
return $copy;
}
}
There is several implementation possible and this is by no means an exclusive list. And remember that with Reflection there is always a way to get around that in PHP, so immutability is all in your head in the end!
It is also often good practice to put immutable objects as final.
EDIT:
changed setX for withX
added comment about final
An immutable object cannot be changed after its initial creation so having setter methods makes no sense as it goes against that base principle.
You could implement some workarounds to simulate immutability in PHP by manipulating class member visibility and overriding the magic __set() method but its not guaranteed immutable as immutability is not a feature of the PHP language.
I believe someone once wrote an extension to provide an immutable value type in PHP though so you could google for that.
Making object immutable in PHP is pretty easy. Here is an elegant and convenient approach.
All you need to do is to create the base abstract class with the specific __get() and __set() magic methods and extend this base class in the child object.
This is quite applicable if you use value objects (e.g. for DDD).
Here is the base class:
abstract class BaseValueObject
{
public function __get(string $propertyName)
{
return $this->$propertyName;
}
public function __set(string $propertyName, $value): void
{
throw new \Exception("Cannot set property {$propertyName}. The object is immutable.");
}
}
Now a child object (well, its class).
class CategoryVO extends BaseValueObject
{
public $id;
public $name;
public function __construct(array $data)
{
$this->id = $data['id'];
$this->name = $data['name'];
}
}
It would throw an exception at attempt to set some value. Basically it is immutable.
This is it.
Make as many immutable objects as you need. Create the new objects via constructor. Dispose them and re-create the new ones when needed (add a specific creator method if required, a static or an instance one, to the base class or to the extended one).
Yet such an object would conveniently expose all its properties as read-only (for some kind of serialization or the like), unlike if we would have made them private (but even though we could use JsonSerializable interface to make the serialization as flexible as we need with private properties or even more drastic transformations).
Finally one cannot mistakenly instantiate BaseValueObject as it is an abstract class. From all standpoints nice elegant solution.
I made a little trait avoiding using Reflection to ease the implementation of immutability: https://github.com/jclaveau/php-immutable-trait
Obviously, as it's not a language feature, it won't impeach mutation by magic but lighten the code of the mutators that must clone the current instance before being applied. Applied to Massimiliano's example it would produce
class ImmutableValueObject
{
use JClaveau\Traits\Immutable;
private $val1;
private $val2;
public function __construct($val1, $val2)
{
$this->val1 = $val1;
$this->val2 = $val2;
}
public function getVal1()
{
return $this->val1;
}
public function withVal1($val1)
{
// Just add these lines at the really beginning of methods supporting
// immutability ("setters" mostly)
if ($this->callOnCloneIfImmutable($result))
return $result;
// Write your method's body as if you weren't in an Immutable class
$this->val1 = $val1;
return $this;
}
public function getVal2()
{
return $this->val2;
}
public function withVal2($val2)
{
if ($this->callOnCloneIfImmutable($result))
return $result;
$this->val2 = $val2;
return $this;
}
}
You can see that you don't return $copy here but $this as Kanstantsin K noticed.
In native PHP https://secure.php.net/manual/en/class.datetimeimmutable.php has mutators that will return new instances with modification applied. So copy pasting sentences saying that immutable objects shouldn't have mutators doesn't seem super interesting.
The practice of using "withXXX" instead of "setXXX" is super interesting, thanks for the suggestion! I personnaly used "becomesXXX" for the api chainging the mutability of the instance (optionnal API in the trait SwitchableMutability).
Hoping it can help some people here!
PS: Suggestions on this little feature are really welcome :) : https://github.com/jclaveau/php-immutable-trait/issues
From an immutable object, you can get its values but there is no way to modify them. Here you can see an example of an immutable class:
<?php
declare(strict_types=1);
final class Immutable
{
/** #var string */
private $value;
public static function withValue(string $value): self
{
return new self($value);
}
public function __construct(string $value)
{
$this->value = $value;
}
public function value(): string
{
return $this->value;
}
}
// Example of usage:
$immutable = Immutable::withValue("my value");
$immutable->value();
If you want setters on a class and object this is perfectly fine, we do this all of the time as we need to set object data. Just simply don't call it immutable.
Many things in the dev world are subjective - our approaches, methodology etc - but "immutable" is a pretty solid definition:
"Immutable":
- Unchanging over time or unable to be changed.
If you want an immutable object it means it cannot be changed after instantiation. This is good for things such as data from a DB that needs to remain set in stone for the duration of the cycle.
If you need to call the object and set or change data on it after instantiation, this is not an immutable object.
Would you take 2 wheels off a car and calling it a motorbike?
There is some talk about methods on an "immutable" class being named without the word "set", but this doesn't stop the functionality of them being a method that sets data. You could call it thisDoesNotSetAnything(int $id) and allow data to be passed in which changes the object. It'll be a setter, and thus the object is mutable.
Here is the class I am unit testing. Currently I am testing the doSomething function:
class FooClass {
public function doSomething( $user ) {
$conn = $this->getUniqueConnection( $user->id );
$conn->doSomethingDestructive();
}
private function getUniqueConnection( $id ) {
return new UniqueConnection( $id );
}
}
As you can see, the doSomething function gets a new instance of UniqueConnection (a class I am not testing here) based on a property of the argument it receives. The problem is that UniqueConnection:: doSomethingDestructive method is something I cannot call during tests due to its... destructiveness. So I would like to stub/mock the UniqueConnection rather than use a real one.
I don't see any way to inject my mocked UniqueConnection. I would make the UniqueConnection a constructor argument for FooClass but, as you can see, a new one gets created based on the parameter to the doSomething function and all the unique ids it may be called with are not known ahead of time.
My only option that I can see is to test a mock of FooClass instead of FooClass itself. Then I would replace the getUniqueConnection function with one that returns a mock/stub. This seems bad to test an mock, but I don't see any way to achieve what I am after otherwise. UniqueConnection is a third party vendor library and cannot be modified.
You could make a UniqueConnectionFactory, and pass an instance of that to FooClass. Then you have
private function getUniqueConnection( $id ) {
return $this->uniqueConnectionFactory->create( $id );
}
In general, this is one of the benefits of using a factory - you keep the new operator out of the class, which allows you to more easily vary the object being created.
Like Rambo Coder said, it's a matter of doing too much in your class. I wouldn't go as far as wanting to create a Factory, especially if you'll only ever create an instance of one specific class. The simplest solution would be to invert the responsibility of creating the UniqueConnection:
<?php
class FooClass {
public function doSomething( UniqueConnection $connection ) {
$connection->doSomethingDestructive( );
}
}
Pass a mock when you're testing, pass a new UniqueConnection( $user->id ) in the real code..
Until you can take the time to refactor the code to use a factory as rambo coder recommends, you can use a partial mock to return a non-destructive unique connection. When you find yourself in this position, it usually means the class under test has more than one responsibility.
function testSomething() {
$mockConn = $this->getMock('UniqueConnection');
$mockConn->expects($this->once())
->method('doSomethingDestructive')
->will(...);
$mockFoo = $this->getMock('FooClass', array('getUniqueConnection'));
$mockFoo->expects($this->once())
->method('getUniqueConnection')
->will($this->returnValue($mockConn));
$mockFoo->doSomething();
}
Creating classes in a way that it can support different modes of execution is very important in some cases. One of these cases is what you are asking for.
Create your classes to support various modes. For example
Class Connection {
private $mode;
public function setMode($mode) {
$this -> $mode = $mode;
}
}
Now, your doSomethingDestructive can act as per the execution mode.
public function doSomethingDestructive() {
if($this -> mode === "test") { //if we are in a test mode scenario
//Log something
// Or just do some logging and give a message
} else {
// do what it was suppose to do
}
}
Next time, when you are testing the class, you dont have to worry about that destructive function doing something destruction accidentally.
public function doSomething( $user ) {
$conn = $this->getUniqueConnection( $user->id );
$conn -> setMode("test"); //Now we are safe
$conn->doSomethingDestructive(); //But the Testing is still being Ran
}
In this case what you want is not a mock object, but a testing subclass. Break your $conn->doSomethingDestructive(); into a method, then subclass FooClass as TestFooClass and override the new method in the subclass. Then you can test using the subclass without getting the unwanted destructive behavior.
For example:
class FooClass {
public function doSomething( $user ) {
$conn = $this->getUniqueConnection( $user->id );
$this->connDoSomethingDestructive($conn);
}
protected function connDoSomethingDestructive($conn) {
$conn->doSomethingDestructive();
}
private function getUniqueConnection( $id ) {
return new UniqueConnection( $id );
}
}
class TestFooClass extends FooClass {
protected function connDoSomethingDestructive() {
}
private function getUniqueConnection( $id ) {
return new MockUniqueConnection( $id );
}
}
When I'm trying to serialize an object which has members including closures an exception is thrown.
To avoid the serialization of the members including closures I tried the following:
function __sleep(){
$ref = new ReflectionClass($this);
$props = $ref->getProperties();
foreach ($props as $prop){
$name = $prop->name;
if (is_callable($this->$name)===false){
$dream[] = $prop->name;
}
}
return $dream;
}
Unfortunately this does not work. Is there a better way to detect whether a property is a closure or not.
EDIT: I solved my problem by letting the closure know whether to serialize or not
To do this I am wrapping the closure itself. Here's an example:
/**
* Wrapper-class to prevent closure to be serialized.
*/
class WrappedClosure {
private $closure = NULL;
protected $reflection = NULL;
public function __construct($function){
if ( ! $function instanceOf Closure)
throw new InvalidArgumentException();
$this->closure = $function;
$this->reflection = new ReflectionFunction($function);
}
/**
* When the instance is invoked, redirect invocation to closure.
*/
public function __invoke(){
$args = func_get_args();
return $this->reflection->invokeArgs($args);
}
// do nothing on serialization
public function __sleep(){}
// do nothing on serialization
public function __wakeup(){}
}
// Assigning a wrapped closure to a member
$myObject->memberHoldingAClosure =
// Wrapping the closure
new WrappedClosure(
function (){
echo "I'am the inner closure.";
}
)
);
// the serialization doesn't throw an exception anymore
serialize($myObject);
Works fine for me:
class foo {
protected $param = 'value';
protected $closure = null;
public function __construct() {
$this->closure = function(){
return 123;
};
}
public function __sleep() {
$serializable = array();
foreach ( $this as $paramName => $paramValue ) {
if ( !is_string($paramValue) && !is_array($paramValue) && is_callable($paramValue) ) {
continue;
}
$serializable[] = $paramName;
}
return $serializable;
}
}
$foo = new foo();
echo serialize($foo);
About checking if value is instance of Closure class (from manual):
Anonymous functions are currently
implemented using the Closure class.
This is an implementation detail and
should not be relied upon.
Therefore I would implement is_closure($value) function as return !is_string($value) && !is_array($value) && is_callable($value) rather than return $value instanceof Closure and hope that some day PHP developers will add native is_closure() function.
Honestly, I think you're trying to solve the wrong problem. If you're sleeping the class, then isn't it wrong to have a successful sleep if you can't serialize everything? Otherwise you can wake up to an inconsistent state (or at least a state that's different than the current one). So I would argue that you should just put everything into the resultant array and then let PHP tell you if it's not serializable.
Otherwise, do you then need to check to see if any stored objects are serialzable? Should you then be checking for Serializable interface or the existence of __sleep? Where do you draw the line? So I would say that you should only not serialize resources and variables that you explicitly know how to recreate in the wakeup function (such as a database connection, or any closures you explicitly know how to recreate). But be careful here, since if you let those closures/resources be changed via the object's API, how can you be sure of a successful wakeup to the prior state.
So in short, I would recommend just returning everything, and letting PHP handle unserializable variables. Otherwise you'd need to either white-list (which isn't going to be practical) or black-list (which isn't going to be complete). And neither is a great solution. Just handle the exception when it comes (throwing and catching exceptions isn't bad).
As far as your exact question, I would implement it as follows:
function is_closure($callback) {
$func = function(){};
return $callback instanceof $func;
}
It still relies on the implementation detail of the closure being of a Object type, but I think that's the best we can do at this point. The best solution would be to petition the core to add a is_closure() function which would be implementation independent...
Well,
I have a problem (ok, no real problem, but I wanna try out something new) with creating objects. Actually I have some orders, which contains a list of orderitems.
These orderitems are used and so spreaded in the whole application, and I need a way to create them. The main problem is, I want to be able to create these objects in many different ways.
Actually I do this in the class constructor and check if the argument which is given.
(I'm using php, so there is no overloading support from the language as you surely know :))
A simple and quick Example
class foo {
protected $_data=null;
public function __contruct($bar){
if (is_array($bar)){
$this->_data=$bar;
}
else {
$dataFromDb=getDataFromDatabase
$this->_data=$dataFromDb;
}
}
}
Anyway, if I want to create my object by giving another type of parameter, lets say a xml-document encapsulated in a string I need to put all this stuff in my constructor.
If the process for creating an object is more complicated, I eventually need to create a seperate method for each type, I want to initiate. But this method is only called when this special type is created. (I think you got the problem :))
Another problem comes to mind, if I need more parameters in the constructor to create a concrete object, I have modify all my code, cause the contructor changed. (Ok, I can give him more and more parameters and work with default values, but that is not what I really want).
So my Question is, which pattern fits this problem to solve my creation of a concrete object. I thought about creating a factory for each way I want to create the concrete object. But I'm not sure if this is a common solution to solve such a problem.
IF its only the signature of the constructor changing i would do it like so (a la the Zend Framework universal constructor):
class foo {
// params
public function __construct($options = null)
{
if(null !== $options)
{
$this->setOptions($options);
}
}
public function setOptions(array $options){
foreach ($options as $name => $value){
$method = 'set' . $name;
if(method_exists($this, $method)
{
$this->$method($value);
}
}
return $this;
}
}
And this essntially means all your constructor parameters are array elements with named keys, and anything you want used in this array during initialization you create a setter for and then its automatically called. The down side is the lack of effective hinting in IDEs.
On the otherhand if you want to have specific constructors then i might go with a factory but still use much the same approach:
class foo {
public static function create($class, $options)
{
if(class_exists($class))
{
$obj = new $class($options);
}
}
}
Of course you could alternatively use PHP's reflection to determine how to call the constructor instead of just injecting an arbitrary array argument.
you could simply make it a factory with optional params :)
class Example_Factory
{
public static function factory($mandatoryParam, $optionalParam = null)
{
$instance = new self;
$instance->setMandatory($mandatoryParam);
if ($optionalParam !== null) {
$instance->setOptional($optionalParam);
}
return $instance;
}
public function setMandatory($in)
{
// do something....
}
public function setOptional($in)
{
// do some more...
}
}