我正在创建域对象。我希望这些对象具有将用于检查要分配给每个属性的值的有效性的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吗? (因为它们不存在于基类中)
答案 0 :(得分:1)
我想我的建议是只使用你现在拥有的两种情况的方法:
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
}
这将立即填充所有字段,而不必为每个属性编写和调用单个函数。
答案 1 :(得分:1)
如果你使用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
- 例如,作为数据库提取方法。
此外,您可能不希望公开DoGroup::makeFriend()
方法。我通常只从DoGroup
类的构造函数调用此方法,所以我喜欢将它私有化。
答案 2 :(得分:0)
创建安全模式($ this-&gt; 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.' );
}
如果数据来自数据库或其他&#34; safe&#34; 将safeMode设置为true。 source(或类扩展数据库类)