Distinguishing which parameters belong to which object - php

This is a pretty specific problem, which I can't find an answer for anywhere.
This applies to lots of languages but I'm particularly wanting to figure it out in PHP.
For the sake of this I'll be using 'events' as our classes. Keeping it simple there are 2 types:
abstract class Event{
protected $cost;
protected $startTime;
public function __construct(){
foreach($eventData as $key => $val){
if(property_exists($this, $key)){
$this->$key = $val;
}
}
}
}
and
class Party extends Event{
private $hasPointyHats;
public function __construct($eventData){
parent::__construct($eventData);
$this->hasPointyHats = $eventData->hasPointyHats;
}
}
Class Event has 2 props: cost and startTime. When it is constructed, it should be passed an associative array containing all of the parameters of the event, and it'll automatically set the property to the passed array value.
Class Party extends Event by establishing whether or not this event will have those awesome pointy party hats (I'm not going if it doesn't).
And no. No it doesn't. Because when you pass this object:
//Some result set...
$mysqli_result = $result->fetch_assoc();
which has cost, startTime, and hasPointyHats values (possibly even more!), you get the following little error:
Fatal error: Cannot access private property Party::$hasPointyHats in C:\somePath\Event.php on line 35
I understand why. Because in "Event", $this refers to the "party" object but it's private.
I am not looking to overwrite every property in the object in the super constructor, just the ones that belong to the super class (abstract class Event) itself. Is there a way to target the specific properties of the Event class and NOT the ones of the child class? That way, no matter what object I extend it with, I wont end up accidentally setting properties on the child class because the passed object had some conflicting property?
I assume it's some silly easy thing like super->property or whatever, but I need to still be able to use property_exists with it.
Thanks for help in advance.

You can use property_exists with just a class name instead of an object.
Like this:
abstract class Event{
protected $cost;
protected $startTime;
public function __construct($eventData){
foreach($eventData as $key => $val){
if(property_exists(__CLASS__, $key)){
$this->$key = $val;
}
}
}
}

property_exists() specifically states in the documentation that as of PHP 5.3, it checks the existence of a property independent of accessibility, which explains the behaviour you're seeing.
get_object_vars(), on the other hand, gets a list of the defined properties in scope, so should work better for your purposes.
Try something like this:
public function __construct() {
$props = get_object_vars($this);
foreach ($eventData as $key => $val) {
if (array_key_exists($key, $props)) {
$this->$key = $val;
}
}
}
This doesn't specifically check that it's a property of the parent class, just that it's accessible from the parent class.
If you really want to restrict to just the parent class, get_class_vars() might be even better:
public function __construct() {
$props = get_class_vars(__CLASS__);
foreach ($eventData as $key => $val) {
if (array_key_exists($key, $props)) {
$this->$key = $val;
}
}
}

Related

Is there any way to define the structure of Array or Object in PHP?

My question is basically exactly the same as the title says.
I was playing with TypeScript for a while now and there's a simple way to define the structure of the Object which is defining properties inside the Interface. I know that PHP does not support the properties in Interfaces, but is there any way to somehow define the structure of the Object (without using some abstract class) I'm passing or at least the Array (which keys need to be presented inside).
What I mean exactly is:
// I already sanitized that this method returns the exact same structure every time
$data = $this->storage->get($some);
// here I'm passing the data I obtained to my Builder
Builder::createFromArray($data);
// or
Builder::create($data);
class Builder {
public static function createFromArray(\ArrayOfSomeType $array) {}
public static function create(\ObjectOfSomeTypeWithPropertiesSpecified $obj) {}
}
Hope I explained it well.
As you said, there is no concept in PHP, that does exactly what you want. There is an ArrayObject class, that would fit your demands of an object with a loose amount of members.
class Builder {
public function create(iterable $data) : \ArrayObject {
$object = (new \ArrayObject())->setFlags(\ArrayObject::ARRAY_AS_PROPS);
foreach ($data as $key => $value) {
$object->offsetSet($key, $value);
}
return $object;
}
}
}
Example 1: Populate object with array
$object = Builder::create([ 'bla' => 'blubb', 'yadda' => 'blubb' ]);
var_dump($object->bla);
The builder returns an object with exact the same properties as the array had keys. All the properties contain the values the array has. You can iterate over the new object with foreach or an Iterator object.
Example 2: Populate object with another object
$class = new \stdClass();
$class->propertyA = 'B';
$class->propertyB = 'B';
$object = Builder::Create($class);
var_dump($object->propertyA);
With PHP nearly all objects are iterable. That means you can iterate over the properties of one object and pass them to our ArrayObject instance.
Common approach of hydration with PHP
There is another approach in PHP which is called hydration. It is a bit more complex than the shown example but pretty handy, if you got it.
// your entity / data model
class Car implements EntityInterface {
protected $horsepower;
public function getHorsepower() : int
{
if ($this->horsepower === null) {
$this->horsepower = 0;
}
return $this->horsepower;
}
public function setHorsepower(int $horsepower) : self
{
$this->horsepower = $horsepower;
return $this;
}
}
This is our data model (entity) of the type car. Our Car inherits from an interface. This is just for type hinting reasons in the hydrator. Our car has one property called horsepower. Of course a car can have more properties. But this is just for example. ;)
class ClassMethodsHydrator
{
public function hydrate(array $data, EntityInterface $entity) : EntityInterface {
foreach ($data as $key => $value) {
$methodName = 'set' . ucwords(strtolower($key));
if (method_exists($entity, $methodName) {
$entity->{$methodName}($value);
}
}
return $entity;
}
}
This is our small hydrator example. This class does, what your builder does. But in a more specific way. It takes an entity and hydrates it with the given data, if it matches a method of the entity.
$entity = (new Hydrator())->hydrate(
[
'horsepower' => 172,
'notexistingproperty' => 'bla',
],
new Car()
);
var_dump($entity->getHorsepower()); // 172
The advantage of hydration is simple. You only have models with known properties. That 's pretty safe and you know at any time, what your model can do for you. It would be senseless, that a car has a rudder for example. In this case a car only got what a car got. Like in the example the car only takes the horsepower member of the array.
I think you could force properites by creating getters and setter in interface. And then instead of
$item->something;
you could use
$item->getSomething();

Class properties as Array instead of variables

I'm starting to work with classes in PHP.
I have been reading and I noticed PHP is all about arrays.
So I was wondering if it would be a good practice to use the class properties inside array and naming them after keys.
Like this:
private $prefix;
private $name;
public function setPrefix($p)
{
$this->prefix = $p;
}
public function getPrefix()
{
return $this->prefix;
}
public function setName($n)
{
$this->name = $n;
}
public function getName()
{
return $this->name;
}
That's the common way of doing this.
But instead do it like this:
private $data = array();
public function setData($property, $value)
{
$this->data[$property] = $value;
}
public function getData($property)
{
return $this->data[$property];
}
Would this be better than the common way? I believe that would be a generic class structure for any database table.
Would this be better than the common way?
NO. And in fact it have drawbacks.
It removes the public, protected and private encapsulation of your properties (which is in the essence of oop).
Adds a layer over every variable access. I don't really know the internals of php, but I really don't think it could be faster than native properties. (although the difference is probably absolutely irrelevant to any script)
IDE's won't be able to complete your code when accessing properties.
It can have it's uses, if your class is a container which needs to have an array of internal data, in which case you would class container implements ArrayAccess and use it like an array, instead of global get/set methods. Here the documentation for ArrayAccess()
$obj = new container();
$obj['key'] = "value";
echo $obj['key'];
Bottom line
Why try and reinvent the wheel? A property is a property. There is no logical or semantical improvement in wrapping every property inside another property. It's obsfucating everything. It won't be faster, it won't be clearer, it removes the oop concepts from your properties and it's just going against the current of using objects in the first place.
About easier database management
If you really want to easily pass an array to a prepared statement, you can get the properties of an object with get_object_vars($obj), no need to put them in an array before for this very purpose. Moreover, as noted by Cypher, you won't be able to use the built-in fetchObject() method, which completely nullify the time you will not have gained by having an easier time querying the database.
This will make it easy to automate DB Operations.
But will make it hard for to use the object by humans.
Yii(2) uses this setup as part of there ActiveRecords but extend it by
defining the properties as a comment
/**
* #property int $id
* #property string $name
*/
class SomeClass extends AbstractModel
And also implements magic methods: __get(), __set()` so you can easily set and get properties like this:
class AbstractModel{
public function __get($name){
if(isset($this->data[$name])){
return $this->data[$name];
}else{
throw new Exception("Undefined or property '$name'");
}
}
public function __set($name, $value){
if(isset($this->data[$name])){
return $this->data[$name] = $value;
}else{
throw new Exception("Undefined or property '$name'");
}
}

Immutable objects in PHP?

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.

Syntax choices for accessing child objects

I'm wondering which is semantically and technically most optimal of my choices here. I've created a simple object registry class, but the method of object access has me wondering what's best. I'm currently using the first variation:
//the Registry methods can chain, each returning a self reference
$registry = Registry::getInstance()->register('myObject', new Object);
//accessing a registered object method
//in various possible ways
Registry::getInstance()->myObject->method(); //1
Registry::getInstance()->use('myObject')->method(); //2
$registry('myObject')->method(); //3
The first variation uses __get() magic, keeping with the fluent syntax.
The second uses the 'getter' method use().
The third uses __invoke() magic, which has been suggested, but I am not too fond of.
I'm just curious to know if anyone has insight, or suggestions towards using any (or none) of these options. The reason for using a Registry class in my case is to provide pseudo-globalization of key objects, for use in nested closures (declaring them with use every time is cumbersome)
This is somewhat related to my other question, at PHP closures and implicit global variable scope
Thanks in advance :)
My personal opinion is to Use a combination of your 2nd and 3rd code-example. Using both (or only your 2nd example) you can use phpDoc to maintain autocompletion.
Here's an example:
<?php
class Session {
public function register() {
}
}
/**
* #property Session $session
*/
class Registry {
private $_classes = array();
public function __set($key, $value) {
$key = (string) $key;
if ((null === $value) && isset($this->_classes[$key])) {
unset($this->_classes[$key]);
} elseif (null !== $value) {
$this->_classes[$key] = $value;
}
}
public function __get($key) {
$key = (string) $key;
if (isset($this->_classes[$key])) {
return $this->_classes[$key];
}
switch ($key) {
case 'session':
$this->_classes[$key] = new Session();
break;
}
return $this->_classes[$key];
}
}
$registry = new Registry();
$registry->session->register();
If I should give you a hint why my Registry-class does not follow the singleton-pattern ... avoid using the singleton-pattern if you want to run unit-tests. See here: http://sebastian-bergmann.de/archives/882-Testing-Code-That-Uses-Singletons.html

Creating Object instance from Posted data - PHP

What is the best way of creating and populating an Object from values passed in from a form?
If for example, i have a class Car with properties Colour, Model, Make, Year and a method Save, which will either insert or update the record.
I then have a form that has fields for all these values and it is submitted. I want to create an instance of class Car with the posted values and then call the Save method. All good and well.
But what is the best way of assigning the posted values to the objects internal properties. Assuming this is a simplified scenario and the actual situation would have many more properties, making individual Set calls long-winded.
Is it best to simply call the Set method for each one? Or pass in an array to a method (or the constructor) which then calls the Set methods? Or some other way?
Any advice on best practices is appreciated
Cheers
Stuart
If the properties are public:
foreach($_POST as $key => $value)
$obj->$key = $value;
If they require setters:
foreach($_POST as $key => $value) {
$set = 'Set' . $key;
$obj->$set($value);
}
You can use a bit of Reflection magic:
public function loadFromArray($array) {
$class = new ReflectionClass(get_class($this));
$props = $class->getProperties();
foreach($props as $p) {
if (isset($array[$p->getName()])
$p->setValue($this, $array[$p->getName]);
}
}
You can implement this method in a base class and make all yout object inherit from that, so you have this functionality in every object without repeating yourself in any class.
I would implement the magic function __set_state(), as it is intended for exactly this use case. There are multiple benefits of putting the implementation into that method:
It is very well defined, what this function does (It is defined in the PHP docs, in contrast to your own source code)
You can access private members within the function
Objects dumped with var_export() will be automatically reconstructed using this function.
EDIT As requested in the comments:
class A {
private $member = 1000;
public static function test(A $a) {
echo $a->member;
}
}
echo A::test(new A()); // outputs 1000
EDIT Fulfilling another request from the comments:
You cannot know on which class a static method was called unless you are using php 5.3, in which the required feature (late static binding) was introduced. What you can do in emulating get_called_class() by analyzing the current stack (using debug_backtrace()). If you have a working get_called_class() function, you can do the following:
class BaseClass {
public static function __set_state($state) {
$class = get_called_class();
// Assumption: Constructor can be invoked without parameters!
$object = new $class();
foreach (get_class_vars($class) as $member) {
if (!isset($state[$member])) {
// Member was not provided, you can choose to ignore this case
throw new Exception("$class::$member was not provided");
} else {
// Set member directly
// Assumption: members are all public or protected
$object->$member = $state[$member];
// Or use the setter-approach given by Chaos.
$setter = 'set' . ucfirst($member);
$object->setter($state[$member]);
}
}
return $object;
}
}
Well, you can convert the post array to an object in one step...
$mypostobject = (object) $_POST;
echo $mypostobject->Colour;
EDIT: added link to PHP docs. http://uk.php.net/manual/en/language.types.object.php
If you want to do this with your own class of object, then some kind of constructor or function that takes the post array and set up your class would be in order.
class MyCar {
public function __construct($postdata)
{
$this->Colour = $postdata['Colour'];
// etc
}
};
$car = new MyCar($_POST);
In case the object that you're posting may become more complex than a flat list of properties in the future (think nesting, arrays as values etc.), you could first create a JavaScript object on the client side and post it as JSON inside a single parameter. Then you can simply deserialize the JSON string into a PHP object. PHP 5+ has built-in support for JSON deserialization. Using JSON would allow you to be flexible in how complex your object can be.
create a constructor which will take all the attributes
class Car {
// private members …
public function __construct($color, $type, $model, $make) {
// assign your values here
}
// other methods
};
if you are dealing with associative arrays, you can also use a constructor with an array as argument:
public function __construct($car_properties) {}
and then loop your properties with
foreach($car_properties as $property => $value) {
if(isset($value)) $this->property = $value
}
be sure to sanitize/validate your input beforehand! (can’t stress this often enough)

Categories