2009-10-29 79 views
2

我有一个验证类,我想用它来检查我的应用程序中的所有值是否在允许的限制范围内。PHP受保护的属性在foreach循环中不可用?

我传递一个目的是一个静态函数验证类内,从另一个类(在这种情况下用户)

function validate() { 
    $errors = Validation::validate($this); 
} 

在验证类,我创建一个新对象,然后通过属性进行的传递参数对象(或者至少这是我想要做的)。

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

我打印出纯粹出于测试目的的函数内的值。我不明白的是为什么该对象在foreach循环外打印出来,但如果我尝试访问循环内的值,则不显示任何内容。

这是在外面显示的foreach循环:

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

验证类不扩展用户类,所以我明白为什么值将不可用,只是没有他们为什么可用外循环但不在里面。

另外,对受保护/私有属性进行验证的最佳方法是什么?

任何意见/提示将不胜感激。

谢谢。

+0

为什么在验证的validate()方法内声明新的Validation实例类?你可能会摆脱创建一个新的Validation()对象的行,并用self来替换对$ validation的调用(假设它们是静态方法)。如果没有,这听起来像你可能想看看Singleton模式。 – 2009-10-29 20:32:03

+0

我最初使用自我(可能会再次),我只是想返回对象而不是数组。 – Dan 2009-10-29 20:45:23

回答

1

您可以通过foreach处理实际对象内的属性来解决此问题。所以每个对象都必须有一个validate()函数,你可以通过一个接口强制执行。例如: -

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

是的。这是访客模式。 – 2009-10-29 20:31:29

+1

drat!我很想成为原创。 ;) – dnagirl 2009-10-29 20:33:54

+1

谢谢, 唯一的事情是我试图不重复自己,不得不在多个类中声明相同的函数似乎有点多余。这对我的应用程序来说并不是什么问题,因为我使用了大量的继承,所以可以将函数粘贴到父类中。 (我想!大声笑) – Dan 2009-10-29 20:38:01

9

从文档(http://us3.php.net/manual/en/language.oop5.visibility.php):

议员申报保护只能在类本身,并通过继承和父类访问。

和从http://us3.php.net/manual/en/function.print-r.php

的print_r(),的var_dump()和var_export()也会显示保护并用PHP 5.静态类成员对象的专用属性将不被显示。

只因为print_r()可以打印某些东西,并不意味着它可以被您的代码访问。考虑print_r(),var_dump()和var_export()是'特殊'函数。

1

您可以使用get_object_vars()函数:

$vars = get_object_vars($obj); 

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

它与保护领域工作得很好。

+1

我不认为这是一个PHP函数。 – 2009-10-29 20:30:18

+1

是的,我想它可能是自己的包装功能。谢谢。该帖子已被编辑。根据手册: – Max 2009-10-29 20:32:38

+0

:根据范围获取给定对象的可访问的非静态属性。 http://ca.php.net/manual/en/function.get-object-vars.php 所以我不认为它会解决问题。 – dnagirl 2009-10-29 20:35:20

0

如果User对象的属性是受保护的或私有的,那么foreach将不会遍历它们。这也许可以解释为什么你不能在foreach语句中访问它们。

如果是这样的情况下,容易解决使用SPL ArrayIterator接口:http://www.php.net/manual/en/class.arrayiterator.php

4

正如Scott桑德斯正确指示PHP文档你不能做,而是让PHP可以通过这个对象的信息var_export

因此你可以滥用eval获得私有和保护对象的属性是这样的:

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


这里有一个简单的例子...

class Test { 
    protected $protectedAttrib = "protectedVal"; 
    private $privateAttrib = "privateVal"; 
    public $publicAttrib = "publicVal"; 
} 

$test = new Test(); 
print_r(get_object_vars_all($test)); 

...输出....

Array 
(
    [protectedAttrib] => protectedVal 
    [privateAttrib] => privateVal 
    [publicAttrib] => publicVal 
) 

真的不应该这样做,因为它击败了使用面向对象的目的,但你可以!

另外请注意,很多人不喜欢使用eval的各种原因,有一个讨论here

+0

在我的工作中,我们现在使用这种技术来悄悄地调查Zend_Cache_Core文件的内容,我不认为这可以通过任何其他方式轻松完成(我有兴趣听到是否有更清晰的方法可以做到这一点!)。 – DespairTyre 2011-09-22 22:39:41

2

的对象使用反射来访问受保护的或私有值:

$refl = new ReflectionObject($object); 
$prop = $refl->getProperty('yourproperty'); 
$prop->setAccessible(true); 
$value = $prop->getValue($object); 

由DespairTyre给予相同的警告适用于该解决方案:为什么有特性的保护或私人的原因。但是,也有一些情况下,您不想更改特定类的代码,但需要访问它的属性...