Dan
Dan

Reputation: 4140

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

Upvotes: 3

Views: 7808

Answers (6)

Philipp
Philipp

Reputation: 580

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

Upvotes: 2

DespairTyre
DespairTyre

Reputation: 51

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.

Upvotes: 4

Petrunov
Petrunov

Reputation: 774

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

Upvotes: 0

Max
Max

Reputation: 2343

You can to use get_object_vars() function:

    $vars = get_object_vars($obj);

    foreach ($vars as $field=>$value){
         ...
    }

It works well with protected fields.

Upvotes: 1

dnagirl
dnagirl

Reputation: 20456

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

Upvotes: 1

Scott Saunders
Scott Saunders

Reputation: 30394

From the docs ( https://www.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 https://www.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.

Upvotes: 9

Related Questions