3

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.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
Dan
  • 4,068
  • 10
  • 41
  • 51
  • Why do you declare a new instance of Validation inside the validate() method of your Validation class? You can probably get rid of the line where you create a new Validation() object, and replace calls to $validation with self (assuming they're static methods). If not, it sounds like you might want to look into the Singleton pattern. – Matt Huggins Oct 29 '09 at 20:32
  • I did originally use self (and may do again), I was just trying to return objects rather than arrays. – Dan Oct 29 '09 at 20:45

6 Answers6

9

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.

Scott Saunders
  • 29,840
  • 14
  • 57
  • 64
4

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.

Community
  • 1
  • 1
  • BTW at my work we now use this technique to unobtrusively investigate the contents of our Zend_Cache_Core files, I don't think this can be easily accomplished in any other way (I'd be interested in hearing if there's a cleaner way to do so!). – DespairTyre Sep 22 '11 at 22:39
2

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

Philipp
  • 580
  • 5
  • 9
1

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;     
  }
}
dnagirl
  • 20,196
  • 13
  • 80
  • 123
  • 1
    Yes indeed. This is the Visitor pattern. – Scott Saunders Oct 29 '09 at 20:31
  • 1
    drat! I so wanted to be original. ;) – dnagirl Oct 29 '09 at 20:33
  • 1
    Thanks, The only thing is I was trying not to repeat myself and having to declare the same functions in multiple classes seems a bit redundant. This isn't such an issue for my application luckily as I use a lot of inheritance so can just stick the functions in the parent class. ( I think! lol) – Dan Oct 29 '09 at 20:38
  • indeed. if User is a model, make a function on Model called validate. you'll be able to access all protected properties from there. just not User private properties. – seanmonstar Feb 13 '10 at 04:16
1

You can to use get_object_vars() function:

    $vars = get_object_vars($obj);

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

It works well with protected fields.

Max
  • 2,293
  • 5
  • 32
  • 48
  • 1
    I don't think that's a PHP function. – Scott Saunders Oct 29 '09 at 20:30
  • 1
    Yep, i'd it was may own wrapper function. Thx. The post is edited. – Max Oct 29 '09 at 20:32
  • according to the manual: Gets the accessible non-static properties of the given object according to scope. http://ca.php.net/manual/en/function.get-object-vars.php So I don't think it will solve the problem. – dnagirl Oct 29 '09 at 20:35
0

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

Petrunov
  • 754
  • 1
  • 8
  • 18