I have a record class with 18 properties.
Before that class can be submitted to the database, all 18 properties must have validated data.
Because I'm OOP-ifying a working procedural webapp, I went about this sort of backwards.
First I addressed workflow for modifying existing records. At the time, it made sense to throw all 18 properties into the __construct method and avoid craploads of setters. A separate loader class handles the dbase business and can return either single objects or an array of record objects. That all worked ok.
But then it came time to address the new record creation workflow, and suddenly I needed to instantiate an empty record, except my record constructor is a hungry beast that wants 18 parameters...
...so you strip the constructor? But then I'd have to add 18 setters and call them all each time I want to work with an existing record...
doesn't seem like much of an improvement! :-/
How do real programmers handle this? (I'm just a weenie hobbyist...)
Either default arguments is one option, but then you have to fill out a large number of null's if you only want to use, say, the first and last.
Then again, you could do array looping:
private $prop1;
private $prop2;
// more properties here.
function __construct( array $props ) // `array` here is for type-hinting.
{
foreach( array( 'prop1', 'prop2' /*, all of the props for this object */
as $property )
{
// basically, this will assign all of the properties as they exist in the
// props array
if( isset( $props[ $property ] ) )
$this->$property = $props[ $property ];
}
}
Or, if you wanted to keep your old constructor signature:
function __construct( $prop1, $prop2 = NULL, $prop3 = NULL /* ... */ )
{
if( is_array( $prop1 ) )
{
$this->array_prop_assignment( $prop1 );
}
else
{
$args = func_get_args();
// this ensures that anything which is passed to the constructor
// will go to the "new" old constructor
call_user_func_array( array( $this, 'param_prop_assignment' ), $args );
}
}
function param_prop_assignment( $prop1, $prop2 /* ... */ )
{
//your old constructor can go here.
}
function array_prop_assignment( array $props )
{
// foreach example above would go here.
}
The new version also gives you the option to simply:
$k = new DataClass(); // no idea what the real class name is.
$k->param_prop_assignment( 1, 2, 3 /* ... */ );
Stuffing 18 parameters in any sort of function is (constructor included) is bad. You'll never remember the correct order when you look at your code few months, or even few days from now on. Further more, as you experienced, when you need to extend the class it's hard.
That's why I usually prefer having classes with getters and setters. Yes it's more typing, but with getter and setters users can easily see what properties they can get and set, plus getter and setters are IDE's auto-complete friendly.
Now, the next problem is you don't want to call setters all the time when you read existing record from the database? You said you have a Loader class, can't you just centralize all the calls to setters in the Loder class?
class Loader{
public function getMyObject(){
$dbData = $this->getDataFromDB();
$myObj = $this->createMyObjectFromDbData($dbData);
return $myObj;
}
private createMyObjectFromDbData($dbData){
$myObj = new MyObject();
/* 18 setter calls */
return $myObj;
}
}
So when you want to work with existing you can simply call Loader.getMyObject();
If you don't feel like typing out all the 18 setter calls in createMyObjectFromDbData, then as long as your setter follows some naming convention you can do
for ($dbData as $columnName => $columnValue){
$propertyName = $columnName;
$propertyValue = $columnValue;
$myObj->set{$columnName}($propertyValue); /* you can't do this in java */
}
You may also want to add a validate method to validate all the properties in the object so you can call that method before you submit it to be inserted into database.
You can chain them to the constructor. Where you do this ...
$Record = Record()->Name('Mark')->Location('A-Town, NY')->Phone('123-345-6789');
You can do this by making a function that has the same name as your class that returns a new instances of your class.
function Record() {
return new Record;
}
class Record {
private $Name;
private $Location;
private $Phone;
public function __get($property) {
return (isset($this->$property)) ? $this->$property : FALSE;
}
public function &__call($property, $arguments)
{
if (property_exists($this, $property))
$this->$property = array_shift($arguments);
return $this;
}
}
$FilledRecord = Record()->Name('Mark')->Location('A-Town')->Phone('123-456-7890');
$EmptyRecord = Record();
print_r($FilledRecord);
print_r($EmptyRecord);
If you need to validate some data, you can just add the function on later.
In a perfect world your object would allow you to specify values using either the constructor or setters. What you could do to simplify things is provide a constructor that only accepts a subset of the 18 values and sets the rest to default values. But that assumes that there are default values that make sense, which may not be the case.
If you have a lot of properties for an object and you don't want to include them all in the constructor, you can use setters return the object itself to make slightly more readable code:
MyClass obj = (new MyClass())
.setName(name)
.setLocation(location)
...
.setPhone(phone)
Along the same lines, if all of the values need to be validated before you have a valid object, you can use a builder object to do the same thing. Basically, you create a builder object, set the values, and then tell the builder to create the actual object. It can then do the validation of all the values (including validation that uses multiple fields) right before it constructs the actual instance of the object.
MyClass obj = (new MyClassFactory())
.setName(name)
.setLocation(location)
...
.setPhone(phone)
.construct();
Related
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();
Basically I have a method which I need to run when the constructor is finished (the method is called persist() and it simply saves a key which was generated during the constructor into the session). It seems simple enough, and it works - at the end of __construct I make the call to $this->persist().
The problem is that this class is subclassed many times. This causes two issues.
One, that I must remember to make the call to persist() at the end of every single subclass's __construct method. Not a huge issue but it doesn't feel very OOP, I feel like I could be dealing with this in the parent class some how and that this would be better.
Two, if a subclass is subclassed (which it is), and the __construct methods chained (i.e. parent::__construct called), the persist() method will be getting fired multiple times, once for each time the class has been subclassed. It only needs to be called once, when all construction is complete. In this scenario it doesn't really break anything because when the persist method is called for the 2nd, 3rd time etc., it simply overwrites what was persisted before. But that isn't the point, because I just feel like there must be a better way and that there are scenarios out there that would not allow for the method to be called multiple times.
Is a factory method which constructs the object and then makes the call to persist on it the only way? I can go down this route but I am just wondering if there is a way to do it without, so that the method from the parent is always called after construction.
Here is some example code:
session_start();
is(!isset($_SESSION["Component"])) $_SESSION["Component"] = [];
abstract Class Component
{
private $id;
protected $key;
function __construct($id = NULL)
{
$this->id = $id;
$this->key = [];
$this->key["something"] = "SomeValue";
$this->persist(); // First call
}
protected function persist()
{
if($this->id !== NULL) $_SESSION["Component"][$this->id] = $this->key;
}
}
Class SomeComponent extends Component
{
function __construct($id = NULL)
{
parent::__construct($id);
$this->key["something-else"] = "SomeOtherValue";
$this->persist(); // Second call
}
}
Class SomeSpecialistComponent extends SomeComponent
{
function __construct($id = NULL, $key = [])
{
parent::__construct($id);
$this->key = array_merge($this->key, $key);
$this->persist(); // Third call
}
}
$my_component = new SomeSpecialistComponent(1, ["example" => true]);
Only trick I found to get something similar (except I wanted to execute things before and not after) is using a parent class with an abstract method as a new constructor :
abstract class RequireThings {
public function __construct() {
$this->constructAndPersist();
$this->persist();
}
abstract function constructAndPersist();
// You could also set this function in your children classes by the way.
public function persist() {
echo ' Then I persist!';
}
}
class UsingPersist extends RequireThings {
public function constructAndPersist() {
echo 'I do my things first.';
}
}
$class = new UsingPersist();
Would output :
I do my things first. Then I persist!
If I got your problem right, it should be enough to avoid problems you are facing.
The main downside of this solution is that you have to use a new function which is supposed to be your new constructor for this type of classes. That's why I set the __constructPersist as abstract, it forces the behavior as wanted.
I would argue in favor of the factory method, mostly because you're doing real work in the constructor. Remove the call where work is being done in the constructors ($this->persist) and place it in the factory:
class ComponentFactory
{
const SOME_COMPONENT = 'component';
const SOME_SPECIALIST_COMPONENT = 'specialist_component';
public static function make($type, $id, $key = null)
{
switch($type) {
case self::SOME_COMPONENT:
$component = new SomeComponent($id);
break;
case self::SOME_SPECIALIST_COMPONENT:
$component = new SomeSpecialistComponent($id, $key);
break;
}
$component->persist();
return $component;
}
}
$component = ComponentFactory::make(ComponentFactory::SOME_COMPONENT, 42);
$specialist = ComponentFactory::make(
ComponentFactory::SOME_SPECIALIST_COMPONENT,
43,
[
'something' => 'SomeValue',
'something-else' => 'SomeOtherValue',
]
);
According to Miško Hevery (author of AngularJS and agile coach at Google) these are the warning signs of doing too much work in the constructor:
new keyword in a constructor or at field declaration
Static method calls in a constructor or at field declaration
Anything more than field assignment in constructors
Object not fully initialized after the constructor finishes (watch
out for initialize methods)
Control flow (conditional or looping logic) in a constructor
CL does complex object graph construction inside a constructor
rather than using a factory or builder
Adding or using an initialization block
just create another function that you'll call before $this->persist and override that in your subclasses instead of the constructor
I'm currently improving my own MVC and I can't find a nice solution for the following scenario:
In most of my models I'm working with a few (already validated by another model) user-based inputs and need to pass them from the controller (where I basically tell the models what to do with the input) to the various models of course. At the moment I'm putting every single user input into a property:
foreach($this->properties as $property => $empty)
{
if(isset($_POST[$property]))
{
$this->properties[$property] = htmlspecialchars(trim($_POST[$property]));
}
}
Eventually when I need a new model to do something, I call it like this:
new view('calendar',$data,$this->properties);
And finally in the model I receive the input / variables by putting them in the models properties…
class validation
{
public function __construct($values)
{
foreach($values as $property => $value)
{
$this->{$property} = $value;
}
}
}
That way I never have to think about where a variable comes from (after the user input has been validated, I don't really care anymore) and can always write a for me clean to read version of $this->user_input
But I somehow have the feeling that this is not the easiest way and propably not a good one either. What bothers me the most is that when writing a new class/model, I always have to tell the model to take the input into their own property and I always have to pass parameters when calling a new class.
Is there some way where I can just inherit these variables from the user when a new class is getting called without having the controller to be a parent class - or would this actually make sense to make the controller a parent? I think it would be confusing when another controller uses the model.
Ok the big thing to remember here, is that your controller "has a" variable container (holding all your properties), as opposed to the controller being (or "is a") a variable container. So first thing, you should be using composition, and not inheritance.
The following snippets below are commented to explain in more detail. Some notes:
The InputData instance could be created above the controller level (say, in a different controller, so that is can be shared among many controllers) which answers the main part of your question. The key point is you're only writing it once, and you can safely say once it's in there, it's good to go
You can include all validation methods inside the InputData, as the role of InputData is to house/store the data safely - which in my opinion a good level of abtraction, or in other words "it's responsible for input data, if something is wrong with the input data, I know where to look"
Finally, for a little extra shine, I added some bit operations so when adding values through the input_data->add, they could be validated against multiple types (for example something could be added which needs to be validated as both a number and a post code).
index.php
require_once( "Controller.php" );
$controller = new Controller();
$controller->print_current_user();
Controller.php
<?
require_once( "Input_Data.php" );
class Controller
{
// Variables
private $input_data;
// Models
// private $model_user;
public function __construct()
{
$this->input_data = new Input_Data();
//$this->model_user = new Model_User();
// Process input (might not happen in the constructor,
// in fact, it might happen higher up, so it can be shared
// Possibly looping over GET / POST data
// for each one, add it to the inputData
$_GET[ 'name' ] = 'Chris';
$_GET[ 'country' ] = 'Australia';
// example iteration 1
$this->input_data->add( 'name', $_GET[ 'name' ], Input_Data::TYPE_VALIDATE_NAME | Input_Data::TYPE_VALIDATE_TEXT );
// example iteration 2
$this->input_data->add( 'country', $_GET[ 'country' ], Input_Data::TYPE_VALIDATE_COUNTRY );
}
// later on in controller, model needs to find the user by name
public function print_current_user()
{
// Example Usage to Model:
// $this->$model_user->get_by_name( $this->input_data->get( 'name' ) );
//
// For now, we'll settle with just printing it out
echo $this->input_data->get( 'name' );
}
}
?>
Input Data
<?
class Input_Data
{
const TYPE_VALIDATE_TEXT = 0;
const TYPE_VALIDATE_NAME = 1;
const TYPE_VALIDATE_EMAIL = 2;
const TYPE_VALIDATE_ADDRESS = 4;
const TYPE_VALIDATE_COUNTRY = 8;
protected $data;
public function __construct() {
$this->data = array();
}
public function add( $name, $value, $type )
{
if( $type & TYPE_VALIDATE_TEXT )
{
// validate input as text
// if valid, flag as such, to be inserted
// or alternatively return a safe version
// depending on your application, an empty string
}
if( $type & TYPE_VALIDATE_NAME )
{
// validate input as name
}
if( $type & TYPE_VALIDATE_EMAIL )
{
// validate input as email
}
if( $type & TYPE_VALIDATE_ADDRESS )
{
// validate input as address
}
if( $type & TYPE_VALIDATE_COUNTRY )
{
// validate input as country
}
// If its valid or is now santised
// insert into the $data variable
// if( $valid ) {
$this->data[ $name ] = $value;
// }
// data[ name ] now contains a safe value that can be accessed
}
public function get( $name )
{
// do checking to ensure it exists
// then return it
return $this->data[ $name ];
}
}
?>
Depending on your needs, it may make sense to store the user inputs in a property of a singleton class (e.g. a UserRequest class):
class UserRequest extends Singleton
{
protected $userProperties;
public function getUserProperties()
{
return $this->userProperties;
}
...other methods...
}
In your bootstrap or routing class, when you capture the user inputs, save them in your Request instance, and then have all controllers extend a base class that reads this property:
class baseController
{
protected $userProperties;
public function __construct()
{
$this->userProperties = Request::getInstance()->getUserProperties();
}
}
Then all controllers will have access to it, and you only have to capture it once.
I think a better solution is to store all the inputs in an object lets just call it data. Each of the models can have a data property. After the controller has completed input validation you can pass the object to the first model and store it there. At that point you can freely pass the object around from model to model. If you're changing values in data you should later update the controllers object with a method call like $this->data = $Model->GetData(); or whatever.
With the MVC paradigm it's not sensible to have models accessing properties of the controller. The controller should basically be initiating all communications ie the controller passes the data to the model who does operations on it, then the controller requests that data and puts it in the view. It would not be good practice to have the controller holding the data and the model operating on it directly.
What bothers me the most is that when writing a new class/model, I always have to tell the model to take the input into their own property and I always have to pass parameters when calling a new class.
So let's say you have two problems here:
Repetition to define properties per each class definition.
Passing parameters for each class creation.
In the most bare and basic sense, you can not circumvent both. If you won't tell the class (at least somehow) which properties it represents, it wouldn't know. Somewhat similar for the second point, if the data is not set to the class, it won't work.
So as it is technically not possible to prevent these two at all, the question is how to make it more comfortable and reduce repetition - if possible.
One route to go would be to just take all these objects to be of the same type. I mean actually those are just some improved arrays, aren't they?
So you can create yourself a base-class you can extend from that contains all the needed code, like importing an array, defining the properties.
So you only need to write the code once and create as many objects and different "types" as you want.
Some example, let's create one such object that has a base-class that does it's job:
class TestModel extends SelfDefinedVariableObjectBase
{
protected $properties = ['bar' => 'hello world'];
}
That's it.Object defined. Now let's use it:
// $_POST['bar'] = '<h1>test</h1> let\'s throw some HTML in';
$foo = new TestModel($_POST);
echo $foo->bar, "\n";
This does import some data from $_POST that is matching with the objects properties (similar to what you have). However the output is the same:
<h1>test</h1> let's throw some HTML in
You might now want that. So therefore you can create some decorators for example, here one that works with a callback function:
class VariableObjectCallbackDecorator
{
private $subject;
private $callback;
public function __construct(VariableObjectBase $object, callable $callback) {
$this->subject = $object;
$this->callback = $callback;
}
public function __get($name) {
return call_user_func($this->callback, $this->subject->__get($name));
}
}
Let's use it with the test-object from the previous example:
$bar = new VariableObjectCallbackDecorator($foo, 'htmlspecialchars');
echo $bar->bar, "\n";
And now this time the output is:
<h1>test</h1> let's throw some HTML in
Hope this is helpful. You can find the code here: Demo
would this actually make sense to make the controller a parent?
Yes, that is probably exactly how I would do it. Then you can use protected for the properties you want to share/inherit.
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;
}
}
}
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)