MVC Model get() and set() vs. straight-up $model->var = val - php

When is the right time to use functions to set variables inside of my models, verse simply directly assigning them?
AKA...
When do I use:
$model->set('status','active');
...instead of:
$model->status = 'active';

using getters and setters is good for the encapsulation of code. It's always a good idea to use them.
Think about this:
What if your model has some variables that you don't want to be able to be read or changed (or both)?
What if you ever need to do something besides just getting and setting the variable? (for example, sanatizing data)?

If you're using a recent version of PHP (5.x), you can get the best of both worlds with the magic methods __get() and __set(). (PHP reference). Any access to an undefined property will be routed to the appropriate get/set function automatically.
I must admin that I'm not certain if this is really a good idea to use or not, but it seems like a decent fit for a base model class in a MVC system.

Related

Is there a way to call a method of a class instance in one line?

I work with a tiny framework, its main object is available for its childs (controllers, models, views) via
mainobject::instance()
Wiki of the framework recommends to add in desired controller method
$mainobject = mainobject::instance()
So it’s become available for models through the single variable. I am in doubt if this is really handy, to define that variable in every single model’s method to get for example global config variable.
class MyAnotherModel extends FrameworksModel
{
…
my_method() {
global $mainobject;
…
if ($mainobject->config['something_here'];
$mainobject->controller->othermodel->othermodelsarray['somestring'];
}
}
Anyway this is a huge string and I’d rather prefer to make it a bit larger calling an instance then to write two strings each time. I mean, write
mainobject::instance->config['goods']
mainobject::instance->controller->othermodel->othermodelsmethodgiveme('power');
But I don’t know if it is possible to implement, since controller class does not provide calling an instance as a variable. I suppose it may be possible via getter method… if there was such method. So what can I do without rewriting original mainobject class?
inb4 long strings are inconveniently to type — there is no problem since I can use abbrevs in emacs and make typing phrase short.

Global Variables vs. Config Variables

I have custom config items in application/config/config.php.
Samples of my custom config items:
$config['website_title'] = 'ABC Website'; //Assume website title is fixed
.
.
.
etc
Now i can call $this->config->item('website_title') any where in my application. However, i don't find it efficient enough because i might have multiple $this->config->item('website_title') within the project. I came up with the following solution:
1.Create a function, within a helper, that return the config item as the following:
public function website_title() {
return $this->config->item('website_title');
}
2.Now i can call website_title() as many as i want.
Is this a good solution? Do you see any downsides?
Note: I try to avoid using global variables because i tried it and i
faced many unnecessary problems such as undefined variables,
surprised!
What do you mean by "efficient"? Runtime efficiency? Coding efficiency? Clarity?
In terms of runtime efficiency Truth's suggestion of using is perhaps the simplest and best. However, I prefer to code using a strict class/object implementation, and in reality defines are just global constants.
If you profile the vast majority of scripts, you will find that however you code your configuration referencing makes an immaterial impact on runtime, so I would suggest going for simplicity and clarity of coding every time.
One approach is to use a singleton class (there are lots of tutorials on doing this) and use the magic method __get() to allow you to dynamically overload parameter access. This is one case where I feel that you have to use a single class as these property methods only work with object (non-static) parameter references. Hence you can simply use:
$cfg = Configuration::get();
...
... $cfg->someConfigParam ... // to refer to a config parameter
...
... /* or even */ ... Configuration::get()->someOtherParameter ...
Note that $cfg in the above example essentially stores an object handle, so there is no material runtime cost in doing this, and you can put this statement at the top of each function or class constructor that references a config item if you don't want to litter your code with Configuration::get()->someOtherParameter type calls.
The Configuration::__get() access function , plus the class constructor can handle all the complexities of caching and access of the individual parameters. This also means that you con also encapsulate the source of the configuration: some application-specific D/B config table; one or more config files, ...; even cookies or URI parameters (so long as you include appropriate validation).
I personally don't recommend over loading with the __set() magic method as, IMO, overriding or setting a config parameter should be an explicit action, e.g. $cfg->setConfigItem( 'someValue', TRUE );
Here is a link to the documentation on my config class if you want some ideas.
I asked this sort of question on programmers once. I got a very good answer, simply use constants.
I.e. WEBSITE_TITLE

Ways to avoid singleton when calling a object inside a global function?

I built some the following i18n function which is called several times when rendering view :
function e_($text)
{
$t = Translate::Instance();
vprintf($t->_($text), array_slice(func_get_args(), 1)); // outputs translated text
}
Currently, I get the instance of the Translate singleton Class inside the function.
I've read that dependency injection should be used instead.
But If I do use dependency injection, I will have to pass the Translate object each time into the function, right ?
This would became :
<?php e_('my text', $this->Translate);
and not simply <?php e_('my text'); ?>
Well I'd like to avoid that.
The way you use the e_ function is actually using an alias. That's fine as long as you can live with it. You don't need to use a singleton to implement an alias:
function e_($text)
{
return $GLOBALS['e_alias']->alias(func_get_args());
}
When setting up the view layer, set the dependency:
$GLOBALS['e_alias'] = $translate;
In application context, set the global variable $translate. This will allow you to move away from the singleton (which are liars), and you actually only need a global variable.
Additionally it allows you to test views with the e_ alias against different translation implementations.
The downside is that you need to manage a list of all these special global variables, like you need to maintain for the global functions like e_.
See as well this answer to the Getting $this inside function question.
True. The reason you would use dependency injection instead is so that you could swap out the translation method for any particular use of e_().
In this particular case, I'm not sure it would be worth it unless you wish to test different translation methods during testing.
One thing you could do to help a little with performance is make $t static so that Translate::Instance() is only ever called once no matter how many calls to e_() are made.

Are there advantages to using __get/__set instead of traditional getter/setter methods except for less code?

coming from Java, I only have a few vacational visits to PHP. Looking at magic get and set methods, my (Java influenced) tummy starts hurting: It looks as if you were accessing properties directly (although, of course, you are actually are using __get and __set).
So - except for less code you have to write, are there any advantages to using magic getter and setter methods instead of traditional getX()/setX() methods? Should I start using them when coding PHP?
Thanks and best!
The only benefit of __get() is the possibility of less code, but even then it's not necessarily the case. For example, if you have a set of 10 private members and you want the getter to reveal 5, you have to write __get() so that if one of the psuedo-visible members is called, you send it. Otherwise, you either issue an error (that would otherwise come naturally without __get() or return a value such as null that may not actually be helpful.
I must excoriate anyone who suggests using getters and setters in general at all. This usually indicates a problem with architecture. Explain the conceptual difference between the two following code blocks, for instance:
class _ {
public $_;
}
vs.
class _ {
private $_;
public function get_() {
return $this->_;
}
}
There isn't a difference.
However, as many will point out the advantage of having a getter is that this allows you to modify the return value in some way transparently to make it useful for the recipient. However, we come back to architecture problems. You should never have to expose the contents of a class for any reason at all. Instead, you should tell the class to perform an action (which may vary based on its state). Using getters generally lends to querying the class' state and performing an action externally based on the viewed state.
I have essentially the same arguments against __set() and setters, but there is one nice thing that __set() lets you do:
class _ {
private $_ = array();
public function __set($key, $val) {
$this->_[$key] = $val;
}
}
This lets you type the very nice $_obj->key = 'val'. Note that there is not much difference from this and adding another method such as add() that takes the key and value and does the same thing, I just prefer the object setter notation.
__get__ and __set__ are fully dynamic. So for example you can start a database request if they are called to enable lazy loading. Of course, you could do this with getters and setters, too, but then you would have to do this every time. You can also do something like AOP because every property call gets passed through one single method. So all in all __get__/__set__ offer more flexilibility against time they take to process. You can do really advanced/cool stuff with it.
The advantages are that when you're refactoring, direct assignments / reads can be handled without the need to immediately change the complete codebase too, the code can be somewhat shorter, and people can create strings somewhat more easily (for example: $title="<title>{$obj->title}</title>"; vs. $title='<title>'.$obj->getTitle().'</title>';.
However, __get & __set methods can become large and unwieldy fairly quickly, and when coding properly & explicitly, it is in my opinion better to use explicit set/getX() methods to make clear functions are called, and the minor increase of code verbosity is as far as I'm concerned justified as one can easily see what actually calls a function and what doesn't. A possible exception could be when you are building a decorator for another class/object, but that's about it.
there is few difference between getter and setter methods and __set() and __get() methods! these are magic methods!
__set() use when you wanna assign undefined state to a object and so __get() also use to fetch value of undefined state!
setter and getter are used to assign or fetch value of defined states
except for less code you have to write, are there any advantages to using magic getter and setter >methods instead of traditional getX()/setX() methods? Should I start using them when coding PHP?
Given that less code to write it's already a strong reason to start use them.
the other reason is that you can add a common behaviour to all your getter/setter
function __set() {
//> Do some code in common between all setter
//> set your var here
}
When writing getX()/setX() for each attribute, practically speaking, you'll have at a minimum, 7 lines of code. This is assuming that your opening method brace is on the same line as the definition and you only put a single line of code into the method, then you have your closing brace on its own line.
For a non-trivial object, multiply that by 6 (YMMV). That is 42 lines just for attribute access/mutation. That does not include input validation or normalization. For an alternative, check out: https://github.com/metaphp/attributes
There are overheads in dynamic programming (e.g. using magic methods). An old benchmark: Benchmarking magic
As PHP is a dynamic (and not a completely enterprise) language, reducing code lines and missing some nanoseconds seems good idea in many cases (for debugging, scalability, reducing errors and etc).

Doctrine 2 Whats the Recommended Way to Access Properties?

I remember reading that in Doctrine 2 models, I should not set properties/fields public. How then would you expose these fields? The sandbox used get*() & set*() methods. Is that the best idea? Its very cumbersome. Using magic methods __get() __set() will make things similar to setting fields public?
Whats your recommendation?
Here's why you can't use public properties: How can public fields “break lazy loading” in Doctrine 2?
You are correct that __get() and __set() can make accessing the protected/private fields easier.
Here's a simple example:
public function __get($name)
{
if(property_exists($this, $name)){
return $this->$name;
}
}
Of course that gives access to all the properties. You could put that in a class that all your entities extended, then define non-assessable fields as private. Or you could use an array to determine which properties should be accessible:$this->accessable = array('name', 'age')
There are plenty of ways to keep all properties protected and still have a reasonably easy way to get/set them.
Personally, I don't like boilerplate code with trivial purpose - it makes the code ugly and tiresome to read. Therefore, I strongly prefer __get/__set. That said, they do have a few drawbacks:
they are significantly slower than normal function calls, though not so much that it should make a difference in practice, as database access is several orders of magnitude slower
__get/__set only gets called when the field is not visible; if you access properties in the code of the entity class, they do not get called, and the proxy has no chance to load itself. (Doctrine tries to avoid this by instantly loading the proxy as soon as one of its public methods are called, but there are some exceptions such as __construct or __wake where that would not make sense, so you can get into trouble by e.g. reading a field in the constructor.)
PHP has some confusing behaviors related to magic methods - e. g. empty($entity->field) will not invoke __get (and thus it will break proxy behavior if used)
If some info should be made public, define a getter for it.
If it's modifiable, add a setter (even better, add a fluent setter!).
API's are cleaner this way, with no magic involved.
I don't like magic in my code.
Just my two cents :)
By "fluent setter" I meant one implementing the fluent interface pattern.
Yes getter and setter methods are the way to access your data. They are a little cumbersome which is why some people do not like doctrine2 or hibernate. But you only need to do it once for each entity and then they are very flexible to produce the output formatting you are hoping for. You can use the cli to do some of this for you. But when you get them rolling I don't find it to big a deal. Especially since you only do this to the properties you need.
Cheers
Rather than having seperate getter and setters, or even using the magic functions.. Is there problem with having something like this in the class
public function Set($attrib, $value)
{
$this->$attrib = $value;
}
public function Get($attrib)
{
return $this->$attrib;
}
It makes it much easy to access the attributes and means they be dynamically set from key-pair arrays.. any comments? or alternative suggestions?
Doctine 2 provides a [command line tool][1] to generate basic entity classes
use the following to get a basic Entity class definition from your mapping, complete with getter/setter functions for each property:
path/to/doctrine_cli orm:generate-entities --generate-methods=true path/to/entities/
You're still responsible for modifying each getter/setter to ensure that they are the proper datatype, as the getter/setter methods generated for the Entity don't do any type casting/converting.

Categories