我正在创建域对象。我希望这些对象具有setter,它将检查要分配给每个属性的值的有效性,但如果假设数据正确,我也希望能够在不执行检查的情况下设置此属性。
我可以做以下事情:
class DO_Group
{
protected $_name = null;
public function getName()
{
return $this->_name;
}
public function setName( $name )
{
$length = strlen( $name );
if( 4 <= $length && $length <= 16 && preg_match( '^[A-Z]*(_[A-Z]*)*$', $name ) == 1 )
$this->_name = $name;
else
throw new Exception( '::DO_Group::setName() - Invalid name.' );
}
}
但是,在已知传递给setName()的$name有效的情况下,我必须调用setName,从而执行不必要的检查来设置该属性。
我可以使用反射API或调试跟踪破解,但我不想使用这两种方法,因为它们在多次使用时性能较差(而且很脏,IMO)。
我想添加一个不检查值的方法:
public function setNameNoCheck( $name )
{
$this->_name = $name;
}
但在这种情况下,将房产公开是没有意义的。如果我选择公开它,代码用户可能会忘记在需要时检查它。
我能做什么吗:
abstract class BaseClass
{
public function setProperty( $name, $value )
{
$this->$name = $value;
}
}
并使我的域对象扩展这个类?PHP引用未声明的属性是正确的吗?(因为它们不存在于基类中)
我想我的建议是对这两个实例都使用现在的方法:
public function setName( $name )
{
$length = strlen( $name );
if( 4 <= $length && $length <= 16 && preg_match( '^[A-Z]*(_[A-Z]*)*$', $name ) == 1 )
$this->_name = $name;
else
throw new Exception( '::DO_Group::setName() - Invalid name.' );
}
在这种情况下,您可以确信您的数据库将始终保持其完整性。即使在少数情况下,如果值为正数,开销也会很小。这似乎是一个干净的解决方案,保证有效。
编辑:
如果对象已经存在于数据库中,为什么不创建一个类方法来处理它呢?然后在直接从数据库中提取值时调用它。。
public function populateFields( $row )
{
$this->_name = $row['name'];
// ... populate other fields here
}
这将一次填充所有字段,而不必为每个属性编写和调用单独的函数。
如果您使用PHP 5.4+,那么这里有一个很好的代码。我几个月前就想到了这个。如果您使用的是PHP 5.3或更低版本,您仍然可以使用call_user_func
使其工作。然而,在匿名函数的帮助下,它变得更加干净和详细。
这个想法是制作一种friend
对象。类似于C++中的friend
类,但操作特定对象而不是类。
让我们开始吧。首先,我们需要为你的课程做一点准备:
class DoGroup
{
protected $_name = null;
public function makeFriend(IDoGroupFriend $newFriend)
{
$newFriend->plugNameSetter(function($name){
$this->_doSetName($name);
});
}
public function setName( $name )
{
// do the costly checking here...
/// and set the variable:
$this->_doSetName($name);
}
protected function _doSetName($name)
{
$this->_name = $name;
}
}
接下来,我们将定义朋友接口:
interface IDoGroupFriend
{
public function plugNameSetter(callable $nameSetterFn);
}
现在我们可以创建朋友:
class ExampleFriend implements IDoGroupFriend
{
private $_nameSetterFn = null;
public function plugNameSetter(callable $nameSetterFn)
{
$this->_nameSetterFn = $nameSetterFn;
}
public function setTheNameFromFriend($name)
{
$nameSetterFn = $this->_nameSetterFn;
$nameSetterFn($name);
}
}
最后,我们可以使用以下朋友:
$Main = new DoGroup();
$Friend = new ExampleFriend();
$Main->makeFriend($Friend);
// tadam!
$Friend->setTheNameViaFriend('name via friend');
当然,你真正的实现可能比盲目地传递名称要复杂得多。如果$name
的源(在这种情况下是ExampleFriend
对象)是可信的,那么我假设它来自不同的可信源。在这种情况下,您将以不同的方式实现setTheNameFromFriend
,例如作为databese fetch方法。
此外,您可能不希望将DoGroup::makeFriend()
方法公开。我通常只从DoGroup
类的构造函数调用这个方法,所以我喜欢将它设为私有方法。
创建安全模式($this->safeMode=false)和
public function setName( $name )
{
if ($this->safeMode===true){ $this->_name = $name; return;}
$length = strlen( $name );
if( 4 <= $length && $length <= 16 && preg_match( '^[A-Z]*(_[A-Z]*)*$', $name ) == 1 )
$this->_name = $name;
else
throw new Exception( '::DO_Group::setName() - Invalid name.' );
}
如果数据来自数据库或其他"安全"源(或类扩展数据库类)