1

I don't know how in else languages, but in PHP seems to me that they are very unsafe way how to set value of any member variable - because one setter cannot easily validate input for many variables (mostly if they are of various types)

Most examples of magic setters say only

public $prop = array();

public function __set($name, $value)
{
    $this->prop[$name] = $value;
}

There is not any validation. And it is wrong.

Even if I would add validation, still I cannot easily validate all types, because code of function would be very very long.

Problem

  • Is any way how to make magic setters safe?
  • or is it really better to avoid their using (define own setter for each member variable)?
3
  • 1
    For reasons of encapsulation, if each variable requires its own validation, it should have its own setter. Mar 1, 2016 at 17:31
  • 3
    As David Pecker said, it is much better to write action related methods rather than setting methods. Setting that aside (pun intended), I would only even consider magic setters in cases where I could not write dedicated methods; i.e. there are dynamic class properties. But I can't think of an example where that is the case... so, until I do, I will never use magic setters.
    – user174739
    Mar 12, 2016 at 21:55
  • Could this be useful to hook invalidation of a cached hash value into the setters when there are no invalid parameters?
    – 5gon12eder
    Mar 12, 2016 at 22:00

3 Answers 3

0

The obvious dirty way to deal with this is to have a switch statement inside your __set method, throwing an exception if an invalid (ie. unsupported) value is trying to be set, through the default case, otherwise either directly assigning the name => value pair of running the pair throu a method to validate it.

If you are using some kind of modern IDE (I can only speak for PhpStorm, but I am sure other IDEs support it too), you can then annotate the class in question with the @property PhpDoc annotation and your IDE will suggest the properties of the class.

Still, if you are modeling a class for your domain, I would refrain from plain setters all together and use more descriptive names of methods, such as change[Property] to overwrite an encapsulated variable, add[Item] to add another item to a private/protected collection and so on.

Either way, for your domain classes, the TellDon'tAsk principle is quite often a very good pattern to follow, followed by throwing domain exceptions on failures.

1
  • Currently I am using NetBeans. Yes, it can call type of variable, read mostly from @var - or also from the first usage of any variable (simply translate $var = array() as array type, or $var = 0 as integer type).
    – Václav
    Mar 1, 2016 at 20:05
0

The use case for magic setters is different than when data has constraints. Typically magic setters are used for Data Transfer Objects. PDO is one such case where the results of a database query can be returned as objects rather than associative arrays. Internally, these PDO objects are using magic setters and getters. Other valid use cases are when there simply are no constraints on the data that can be assigned to the property.

As soon as you restrict values based on some set of rules, magic setters become a burden. Traditional private fields and mutator methods become the recommended approach so you can enforce encapsulation and data hiding.

The question about making magic setters safe is not well defined. Security is a concern, of course, but that gets limited to how the application uses the keys and values of the internal $prop array.

The one thing I would recommend is to make $prop a private field. Just because you are using magic setters doesn't mean the backing array needs to be public.

-1

What do you mean with no validation? PHP isn't strictly typed, it is up to mostly you, to validate inputs. If you write your owner setter/method/function, you will still need to validate. From the perspective of validation - I don't see a difference between magic methods, and any regular function. Btw, in PHP you can enforce array type and objects in method arguments.

Edit You do use magic methods, when it is appropriate. No one is forcing you to use them instead of a regular method. There will be situations when you might want to use them.

As to your question, my point is still the same: whether it is a magic method, or a regular method of your class that accepts arguments, it is your responsibility to validate them. It has nothing to do with the safety of magic methods.

4
  • 1
    Those words about missing validation is strictly related to example above. And else, I am worried about that you are wrong about difference between regular method and magic one, in case of setters.
    – Václav
    Mar 12, 2016 at 16:30
  • What are you talking about? I think we are talking about different things. Regular PHP methods and magic methods alike - are all prone to variable mishaps. You need to validate your input whether its a magic method or not.
    – Muhammed
    Mar 12, 2016 at 21:11
  • Look top - magic setter behaves in a different way- _set behave like $object -> variable = $value - but __call behaves like a standard function and covers all functions, unless there is limitation (inside of __call) that it cannot be used on group of functions (mostly private and protected).
    – Václav
    Mar 12, 2016 at 21:33
  • We are discussing here validation of arguments, as was asked in the question and my response is valid. I know how magic functions behave, you dont need to explain me that.
    – Muhammed
    Mar 13, 2016 at 6:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.