OO PHP protected properties not available in foreach loop?
I have a validation class which I would like to use to check all values in my application are within allowed constraints.
I am passing an object to a static function within the validation class, from another class (in this case User)
function validate() {
$errors = Validation::validate($this);
}
In the validation class, I create a new object and then proceed through the properties of the passed parameter object (or at least that is what I would like to do).
function validate($object) {
$validation = new Validation();
print_r($object);
print_r('<br />');
foreach($object as $key => $val) {
print_r($val);
isset($val->maxlength) ? $validation->validateLengthNoMoreThan($val->value, $val->maxlength) : null;
isset($val->minlength) ? $validation->validateLengthAtLeast($val->value, $val->minlength) : null;
isset($val->required) && ($val->required == true) ? $validation->validateNotBlank($val->value) : null;
}
return $validation->errors;
}
I am printing out values within the function purely for test purposes. What I don't understand is why the object prints out fine outside of the fore开发者_Python百科ach loop, but if I try to access the values within the loop, nothing is displayed.
This is what is displayed OUTSIDE of the foreach loop:
User Object ( [username:protected] => Property Object ( [value] => aaa [maxlength] => 12 [minlength] => 3 [required] => 1 ) [firstname:protected] =Property Object ( [value] => aaa [maxlength] => 12 [minlength] => 3 [required] => 1 ) [lastname:protected] =Property Object ( [value] => aaa [maxlength] => 12 [minlength] => 3 [required] => 1 ) )
The validation class does NOT extend the User class, so I understand why the values would not be available, just not why they are available outside of the loop but not inside of it.
Also, what would be the best way to carry out validation on protected/private properties?
Any advice/tips would be greatly appreciated.
Thanks.
From the docs ( http://us3.php.net/manual/en/language.oop5.visibility.php ):
Members declared protected can be accessed only within the class itself and by inherited and parent classes.
and from http://us3.php.net/manual/en/function.print-r.php :
print_r(), var_dump() and var_export() will also show protected and private properties of objects with PHP 5. Static class members will not be shown.
Just because print_r() can print something, doesn't mean it can be accessed by your code. consider print_r(), var_dump() and var_export() to be 'special' functions.
As Scott Saunders correctly indicates the PHP docs say you can't do it but PHP makes this object information available via var_export.
Consequently you can abuse eval to get private and protected object attributes like this:
function get_object_vars_all($obj) {
$objArr = substr(str_replace(get_class($obj)."::__set_state(","",var_export($obj,true)),0,-1);
eval("\$values = $objArr;");
return $values;
}
Here's a quick example...
class Test {
protected $protectedAttrib = "protectedVal";
private $privateAttrib = "privateVal";
public $publicAttrib = "publicVal";
}
$test = new Test();
print_r(get_object_vars_all($test));
...outputs....
Array
(
[protectedAttrib] => protectedVal
[privateAttrib] => privateVal
[publicAttrib] => publicVal
)
You really shouldn't do this because it defeats the purpose of using OO, but you can!
In addition note that many people don't like using eval for various reasons, there's a discussion here.
Use a reflection on the Object to access protected or private values:
$refl = new ReflectionObject($object);
$prop = $refl->getProperty('yourproperty');
$prop->setAccessible(true);
$value = $prop->getValue($object);
The same warning as given by DespairTyre applies to this solution: There are reasons why properties are protected or private. However, there are also situations where you don't want to change the code of a specific class but need to access it's properties...
You can get around this issue by foreach'ing the properties inside the actual object. So each object must have a validate() function, which you could enforce with an interface. E.g.:
class MyClass implements Validator {
$var1;
$var2;
public function validate(){ //required by Validator interface
$validation = new Validation();
foreach($this as $k=>$v) {
//run validations
}
return $validation->errors;
}
}
You can to use get_object_vars() function:
$vars = get_object_vars($obj);
foreach ($vars as $field=>$value){
...
}
It works well with protected fields.
If the properties of the User object are protected or private, then the foreach won't traverse them. That may explain why you cannot access them within the foreach statement.
If this is the case, it is easily solvable by using SPL ArrayIterator interface : http://www.php.net/manual/en/class.arrayiterator.php
精彩评论