Syntax choices for accessing child objects - php

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

Related

Distinguishing which parameters belong to which object

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;
}
}
}

Properties in PHP

Since PHP has no notion of properties like C# what is the best way to expose certain attributes of a class? Is it recommended to have separate get and set functions or should the member variable be made public?
I am designing a class whose objects will be contained in another class. There should be a way to set/get properties of the object.
On the whole I would recommend exposing public variables on your PHP class, except where you need to perform a more complex action, in which case you would use getter and setter functions.
So where you would use this in C#
public string MyProp { get; set; }
I would recommend this in PHP
public $MyProp;
Using public attribute or private with getter/setter will both do the trick.
I will proceed like this :
If the attribute is critical, use a getter and setter like this :
class myClass
{
private $myAttr;
public function getmyAttr()
{
return $this->myAttr;
}
public function setmyAttr($attr)
{
//Do some verification on $attr
$this->myAttr = $attr;
}
}
If the attribute is less critical , you could simply set is visibility to public.
Because of the lack of strong type in php i will always prefer the private attribute with getter and setter. it let you ensure that the attribute is always what it should be (not "1" instead of 1 for example).
It depends, it is not very rare to make attributes public which are not very security sensitive. But if you do want to keep them private you could create something like this:
class withAttributes{
private $property;
public function getPrivateProperty{
return $this->property;
}
}
In the other class:
$object = new withAttributes();
$attribute = $object->getPrivateProperty();
Hope this helps
There's no idiomatic way built in the language, however you could try using the magic __get and __set methods to emulate something simillar.
Consider this pretty dumb example:
Class Foo {
private $bar;
private $baz;
public function __get($name) {
if (property_exists($this, $name)) {
if ($name == 'bar') {
return strtoupper($this->{$name});
} else {
return $this->{$name};
}
}
return null; // this is what php would do, consider throwning an exception instead
}
public function __set($name, $value) {
if (property_exists($this, $name)) {
if ($name == 'bar') {
$this->{$name} = strtolower($value);
} else {
$this->{$name} = $value;
}
}
// we just ignore this call, consider throwing exceptions, or you could make the class open to property addition in runtime too
}
}
$f = new Foo;
$f->bar = 'tickle me elmo';
print $f->bar; // prints uppercase
This way later on, if you decide to implement some read/write logic, you can hook it in the magic methods. From performance standpoint, these magic methods are slower than ordinary method calls, also arguably more surprising for the users of these classes than explicit getter/setter methods.
If you want to create something more like the built-in StdObject or basic array consider implementing the ArrayAccess interface for the [] syntax.

detect closure in __sleep to prevent their serialization

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...

What are the advantages of using getters and setters instead of functions or simply public fields in PHP? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 10 months ago.
This post was edited and submitted for review 6 months ago and failed to reopen the post:
Original close reason(s) were not resolved
Improve this question
I'm not a PHP developer, so I'm wondering what the advantages and disadvantages are in PHP to using explicit getter/setters, in a pure OOP style, with private fields (the way I like):
class MyClass {
private $firstField;
private $secondField;
public function getFirstField() {
return $this->firstField;
}
public function setFirstField($x) {
$this->firstField = $x;
}
public function getSecondField() {
return $this->secondField;
}
public function setSecondField($x) {
$this->secondField = $x;
}
}
or just public fields:
class MyClass {
public $firstField;
public $secondField;
}
You can use php magic methods __get and __set.
<?php
class MyClass {
private $firstField;
private $secondField;
public function __get($property) {
if (property_exists($this, $property)) {
return $this->$property;
}
}
public function __set($property, $value) {
if (property_exists($this, $property)) {
$this->$property = $value;
}
return $this;
}
}
?>
Why use getters and setters?
Scalability: It's easier refactor a getter than search all the var assignments in a project code.
Debugging: You can put breakpoints at setters and getters.
Cleaner: Magic functions are not good solution for writting less, your IDE will not suggest the code. Better use templates for fast-writting getters.
Google already published a guide on optimization of PHP and the conclusion was:
No getter and setter Optimizing PHP
And no, you must not use magic methods. For PHP, Magic Methods are evil. Why?
They are hard to debug.
There is a negative performance impact.
They require writing more code.
PHP is not Java, C++, or C#. PHP is different and plays with different rules.
Encapsulation is important in any OO language, popularity has nothing to do with it. In dynamically typed languages, like PHP, it is especially useful because there is little ways to ensure a property is of a specific type without using setters.
In PHP, this works:
class Foo {
public $bar; // should be an integer
}
$foo = new Foo;
$foo->bar = "string";
In Java, it doesn't:
class Foo {
public int bar;
}
Foo myFoo = new Foo();
myFoo.bar = "string"; // error
Using magic methods (__get and __set) also works, but only when accessing a property that has lower visibility than the current scope can access. It can easily give you headaches when trying to debug, if it is not used properly.
If you preffer to use the __call function, you can use this method. It works with
GET => $this->property()
SET => $this->property($value)
GET => $this->getProperty()
SET => $this->setProperty($value)
kalsdas
public function __call($name, $arguments) {
//Getting and setting with $this->property($optional);
if (property_exists(get_class($this), $name)) {
//Always set the value if a parameter is passed
if (count($arguments) == 1) {
/* set */
$this->$name = $arguments[0];
} else if (count($arguments) > 1) {
throw new \Exception("Setter for $name only accepts one parameter.");
}
//Always return the value (Even on the set)
return $this->$name;
}
//If it doesn't chech if its a normal old type setter ot getter
//Getting and setting with $this->getProperty($optional);
//Getting and setting with $this->setProperty($optional);
$prefix = substr($name, 0, 3);
$property = strtolower($name[3]) . substr($name, 4);
switch ($prefix) {
case 'get':
return $this->$property;
break;
case 'set':
//Always set the value if a parameter is passed
if (count($arguments) != 1) {
throw new \Exception("Setter for $name requires exactly one parameter.");
}
$this->$property = $arguments[0];
//Always return the value (Even on the set)
return $this->$name;
default:
throw new \Exception("Property $name doesn't exist.");
break;
}
}
In addition to the already great and respected answers in here, I would like to expand on PHP having no setters/getters.
PHP does not have getter and setter syntax. It provides subclassed or magic methods to allow "hooking" and overriding the property lookup process, as pointed out by Dave.
Magic allows us lazy programmers to do more with less code at a time at which we are actively engaged in a project and know it intimately, but usually at the expense of readability.
Performance Every unnecessary function, that results from forcing a getter/setter-like code-architecture in PHP, involves its own memory stack-frame upon invocation and is wasting CPU cycles.
Readability: The codebase incurs bloating code-lines, which impacts code-navigation as more LOC mean more scrolling,.
Preference: Personally, as my rule of thumb, I take the failure of static code analysis
as a sign to avoid going down the magical road as long as obvious long-term benefits elude me at that time.
Fallacies:
A common argument is readability. For instance that $someobject->width is easier to read than $someobject->width(). However unlike a planet's circumference or width, which can be assumed to be static, an object's instance such as $someobject, which requires a width function, likely takes a measurement of the object's instance width.
Therefore readability increases mainly because of assertive naming-schemes and not by hiding the function away that outputs a given property-value.
__get / __set uses:
pre-validation and pre-sanitation of property values
strings e.g.
"
some {mathsobj1->generatelatex} multi
line text {mathsobj1->latexoutput}
with lots of variables for {mathsobj1->generatelatex}
some reason
"
In this case generatelatex would adhere to a naming scheme of actionname + methodname
special, obvious cases
$dnastringobj->homeobox($one_rememberable_parameter)->gattaca->findrelated()
$dnastringobj->homeobox($one_rememberable_parameter)->gttccaatttga->findrelated()
Note: PHP chose not to implement getter/setter syntax. I am not claiming that getters/setter are generally bad.
class MyClass {
private $firstField;
private $secondField;
private $thirdField;
public function __get( $name ) {
if( method_exists( $this , $method = ( 'get' . ucfirst( $name ) ) ) )
return $this->$method();
else
throw new Exception( 'Can\'t get property ' . $name );
}
public function __set( $name , $value ) {
if( method_exists( $this , $method = ( 'set' . ucfirst( $name ) ) ) )
return $this->$method( $value );
else
throw new Exception( 'Can\'t set property ' . $name );
}
public function __isset( $name )
{
return method_exists( $this , 'get' . ucfirst( $name ) )
|| method_exists( $this , 'set' . ucfirst( $name ) );
}
public function getFirstField() {
return $this->firstField;
}
protected function setFirstField($x) {
$this->firstField = $x;
}
private function getSecondField() {
return $this->secondField;
}
}
$obj = new MyClass();
echo $obj->firstField; // works
$obj->firstField = 'value'; // works
echo $obj->getFirstField(); // works
$obj->setFirstField( 'value' ); // not works, method is protected
echo $obj->secondField; // works
echo $obj->getSecondField(); // not works, method is private
$obj->secondField = 'value'; // not works, setter not exists
echo $obj->thirdField; // not works, property not exists
isset( $obj->firstField ); // returns true
isset( $obj->secondField ); // returns true
isset( $obj->thirdField ); // returns false
Ready!
I made an experiment using the magic method __call.
Not sure if I should post it (because of all the "DO NOT USE MAGIC METHODS" warnings in the other answers and comments) but i'll leave it here.. just in case someone find it useful.
public function __call($_name, $_arguments){
$action = substr($_name, 0, 4);
$varName = substr($_name, 4);
if (isset($this->{$varName})){
if ($action === "get_") return $this->{$varName};
if ($action === "set_") $this->{$varName} = $_arguments[0];
}
}
Just add that method above in your class, now you can type:
class MyClass{
private foo = "bar";
private bom = "bim";
// ...
// public function __call(){ ... }
// ...
}
$C = new MyClass();
// as getter
$C->get_foo(); // return "bar"
$C->get_bom(); // return "bim"
// as setter
$C->set_foo("abc"); // set "abc" as new value of foo
$C->set_bom("zam"); // set "zam" as new value of bom
This way you can get/set everything in your class if it exist so, if you need it for only a few specific elements, you could use a "whitelist" as filter.
Example:
private $callWhiteList = array(
"foo" => "foo",
"fee" => "fee",
// ...
);
public function __call($_name, $_arguments){
$action = substr($_name, 0, 4);
$varName = $this->callWhiteList[substr($_name, 4)];
if (!is_null($varName) && isset($this->{$varName})){
if ($action === "get_") return $this->{$varName};
if ($action === "set_") $this->{$varName} = $_arguments[0];
}
}
Now you can only get/set "foo" and "fee".
You can also use that "whitelist" to assign custom names to access to your vars.
For example,
private $callWhiteList = array(
"myfoo" => "foo",
"zim" => "bom",
// ...
);
With that list you can now type:
class MyClass{
private foo = "bar";
private bom = "bim";
// ...
// private $callWhiteList = array( ... )
// public function __call(){ ... }
// ...
}
$C = new MyClass();
// as getter
$C->get_myfoo(); // return "bar"
$C->get_zim(); // return "bim"
// as setter
$C->set_myfoo("abc"); // set "abc" as new value of foo
$C->set_zim("zam"); // set "zam" as new value of bom
.
.
.
That's all.
Doc:
__call() is triggered when invoking inaccessible methods in an object context.
Well, PHP does have magic methods __get, __set, __isset & __unset, which is always a start. Alas proper (get it?) OO properties is more than magic methods. The main problem with PHP's implementation is that magic methods are called for all inaccessible properties. Which means you have to Repeat Yourself (eg. by calling property_exists()) in the magic methods when determining if name is actually a property of your object. And you can't really solve this general problem with a base class unless all your classes inherit from ie. ClassWithProperties, since PHP lacks multiple inheritance.
In contrast, Python new style classes gives you property(), which lets you explicitly define all your properties. C# has special syntax.
http://en.wikipedia.org/wiki/Property_(programming)
After reading the other advices, I'm inclined to say that:
As a GENERIC rule, you will not always define setters for ALL properties, specially "internal" ones (semaphores, internal flags...). Read-only properties will not have setters, obviously, so some properties will only have getters; that's where __get() comes to shrink the code:
define a __get() (magical global getters) for all those properties which are alike,
group them in arrays so:
they'll share common characteristics: monetary values will/may come up properly formatted, dates in an specific layout (ISO, US, Intl.), etc.
the code itself can verify that only existing & allowed properties are being read using this magical method.
whenever you need to create a new similar property, just declare it and add its name to the proper array and it's done. That's way FASTER than defining a new getter, perhaps with some lines of code REPEATED again and again all over the class code.
Yes! we could write a private method to do that, also, but then again, we'll have MANY methods declared (++memory) that end up calling another, always the same, method. Why just not write a SINGLE method to rule them all...? [yep! pun absolutely intended! :)]
Magic setters can also respond ONLY to specific properties, so all date type properties can be screened against invalid values in one method alone. If date type properties were listed in an array, their setters can be defined easily. Just an example, of course. there are way too many situations.
About readability... Well... That's another debate: I don't like to be bound to the uses of an IDE (in fact, I don't use them, they tend to tell me (and force me) how to write... and I have my likes about coding "beauty"). I tend to be consistent about naming, so using ctags and a couple of other aids is sufficient to me... Anyway: once all this magic setters and getters are done, I write the other setters that are too specific or "special" to be generalized in a __set() method. And that covers all I need about getting and setting properties. Of course: there's not always a common ground, or there are such a few properties that is not worth the trouble of coding a magical method, and then there's still the old good traditional setter/getter pair.
Programming languages are just that: human artificial languages. So, each of them has its own intonation or accent, syntax and flavor, so I won't pretend to write a Ruby or Python code using the same "accent" than Java or C#, nor I would write a JavaScript or PHP to resemble Perl or SQL... Use them the way they're meant to be used.
Generally speaking, the first way is more popular overall because those with prior programming knowledge can easily transition to PHP and get work done in an object-oriented fashion. The first way is more universal. My advice would be to stick with what is tried and true across many languages. Then, when and if you use another language, you'll be ready to get something accomplished (instead of spending time reinventing the wheel).
There are many ways to create sourcecode in a netbeans-convention. This is nice. It makes thinks such easyer === FALSE. Just use the traditionel, specially if you are not sure which one of the properties should be encapsuled and which one not. I know, it is a boi.... pla... code, but for debugging-works and many other thinks it is the better, clear way. Dont spend to much time with thousend of arts how to make simple getters and setters. You cannot implement too some design patterns like the demeter-rule and so on, if you use magics. In specific situation you can use magic_calls or for small, fast and clear solutions. Sure you could make solutions for design-patters in this way too, but why to make you live more difficult.
Validating + Formatting/Deriving Values
Setters let you to validate data and getters let you format or derive data. Objects allow you to encapsulate data and its validation and formatting code into a neat package that encourages DRY.
For example, consider the following simple class that contains a birth date.
class BirthDate {
private $birth_date;
public function getBirthDate($format='Y-m-d') {
//format $birth_date ...
//$birth_date = ...
return $birth_date;
}
public function setBirthDate($birth_date) {
//if($birth_date is not valid) throw an exception ...
$this->birth_date = $birth_date;
}
public function getAge() {
//calculate age ...
return $age;
}
public function getDaysUntilBirthday() {
//calculate days until birth days
return $days;
}
}
You'll want to validate that the value being set is
A valid date
Not in the future
And you don't want to do this validation all over your application (or over multiple applications for that matter). Instead, it's easier to make the member variable protected or private (in order to make the setter the only access point) and to validate in the setter because then you'll know that the object contains a valid birth date no matter which part of the application the object came from and if you want to add more validation then you can add it in a single place.
You might want to add multiple formatters that operate on the same member variable i.e. getAge() and getDaysUntilBirthday() and you might want to enforce a configurable format in getBirthDate() depending on locale. Therefore I prefer consistently accessing values via getters as opposed to mixing $date->getAge() with $date->birth_date.
getters and setters are also useful when you extend objects. For example, suppose your application needed to allow 150+ year birth dates in some places but not in others. One way to solve the problem without repeating any code would be to extend the BirthDate object and put the additional validation in the setter.
class LivingBirthDate extends BirthDate {
public function setBirthDate($birth_date) {
//if $birth_date is greater than 150 years throw an exception
//else pass to parent's setter
return parent::setBirthDate($birth_date);
}
}
This post is not specifically about __get and __set but rather __call which is the same idea except for method calling. As a rule, I stay away from any type of magic methods that allow for overloading for reasons outlined in the comments and posts HOWEVER, I recently ran into a 3rd-party API that I use which uses a SERVICE and a SUB-SERVICE, example:
http://3rdparty.api.com?service=APIService.doActionOne&apikey=12341234
The important part of this is that this API has everything the same except the sub-action, in this case doActionOne. The idea is that the developer (myself and others using this class) could call the sub-service by name as opposed to something like:
$myClass->doAction(array('service'=>'doActionOne','args'=>$args));
I could do instead:
$myClass->doActionOne($args);
To hardcode this would just be a lot of duplication (this example very loosely resembles the code):
public function doActionOne($array)
{
$this->args = $array;
$name = __FUNCTION__;
$this->response = $this->executeCoreCall("APIService.{$name}");
}
public function doActionTwo($array)
{
$this->args = $array;
$name = __FUNCTION__;
$this->response = $this->executeCoreCall("APIService.{$name}");
}
public function doActionThree($array)
{
$this->args = $array;
$name = __FUNCTION__;
$this->response = $this->executeCoreCall("APIService.{$name}");
}
protected function executeCoreCall($service)
{
$cURL = new \cURL();
return $cURL->('http://3rdparty.api.com?service='.$service.'&apikey='.$this->api.'&'.http_build_query($this->args))
->getResponse();
}
But with the magic method of __call() I am able to access all services with dynamic methods:
public function __call($name, $arguments)
{
$this->args = $arguments;
$this->response = $this->executeCoreCall("APIService.{$name}");
return $this;
}
The benefit of this dynamic calling for the return of data is that if the vendor adds another sub-service, I do not have to add another method into the class or create an extended class, etc. I am not sure if this is useful to anyone, but I figured I would show an example where __set, __get, __call, etc. may be an option for consideration since the primary function is the return of data.
EDIT:
Coincidentally, I saw this a few days after posting which outlines exactly my scenario. It is not the API I was referring to but the application of the methods is identical:
Am I using api correctly?
Update: Don't use this answer since this is very dumb code that I found while I learn. Just use plain getter and setter, it's much better.
I usually using that variable name as function name, and add optional parameter to that function so when that optional parameter is filled by caller, then set it to the property and return $this object (chaining) and then when that optional parameter not specified by caller, i just return the property to the caller.
My example:
class Model
{
private $propOne;
private $propTwo;
public function propOne($propVal = '')
{
if ($propVal === '') {
return $this->propOne;
} else {
$this->propOne = $propVal;
return $this;
}
}
public function propTwo($propVal = '')
{
if ($propVal === '') {
return $this->propTwo;
} else {
$this->propTwo = $propVal;
return $this;
}
}
}

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