PHP中的延迟加载公共类数据成员
我想在PHP中延迟加载类的公共数据成员。假设我们有以下类:PHP中的延迟加载公共类数据成员,php,lazy-loading,public-members,Php,Lazy Loading,Public Members,我想在PHP中延迟加载类的公共数据成员。假设我们有以下类: <?php class Dummy { public $name; public $age; public $status_indicator; } ?> 如果$name、$age和$status\u indicator是私有数据成员,我会通过它们的getter方法延迟加载它们,但由于它们是公共的,我不清楚如何延迟加载它们。这可能吗 编辑: 有人评论说,有一个名为\uu get的方法可能有助于解
<?php
class Dummy
{
public $name;
public $age;
public $status_indicator;
}
?>
如果$name
、$age
和$status\u indicator
是私有数据成员,我会通过它们的getter方法延迟加载它们,但由于它们是公共的,我不清楚如何延迟加载它们。这可能吗
编辑:
有人评论说,有一个名为\uu get
的方法可能有助于解决这个问题,但我不理解。您可以使用它来模拟在首次访问时真正动态加载的公共成员。当您试图访问对象的未定义成员时,PHP将调用\uu get
,并将您试图访问的成员的名称传递给它。例如,如果类定义了一个\uuu-get
方法,那么访问$x->myu-variable
将调用\uu-get(“myu-variable”)
在本例中,$dummy->name
间接调用getter方法getName
,该方法在第一次访问时初始化名为$\u name
的私有成员:
<?php
class Dummy
{
private $_name;
public function __get($var) {
if ($var == 'name') {
return $this->getName();
} else if ($var == 'age') {
// ...
} else {
throw "Undefined variable $var";
}
}
public function getName() {
if (is_null($this->_name)) {
// Initialize and cache the value for $name
$this->_name = expensive_function();
}
return $this->_name;
}
}
$dummy = new Dummy();
echo $dummy->name;
以下是我在最近一个项目中使用的一些代码:
类增强对象{
#在此处存储缓存属性
私有$lazyProperties=array();
#允许$object->prop将别名转换为$object->getProperty()。
#另外,允许将$object->loadProp()缓存到$object->prop
公共函数获取($property){
$getter=“get”.ucfirst($property);
$loader=“load”.ucfirst($property);
如果(方法_存在($this$getter)){
返回$this->$getter();
}
elseif(方法_存在($this$loader)){
如果(!isset($this->lazyProperties[$property])){
$this->lazyProperties[$property]=$this->$loader();
}
返回$this->lazyProperties[$property];
}
}
#允许$object->prop=$value到$object->setProperty的别名($value)。
公共函数集($property,$value){
$setter=“set”.ucfirst($property);
$loader=“load”.ucfirst($property);
如果(方法_存在($this$setter)){
返回$this->$setter($value);
}
elseif(方法_存在($this$loader)){
$this->lazyProperties[$property]=$value;
}
退还$this;
}
}
这意味着您只需将神奇的\uu get
和set
弄乱一次,然后简单地命名您的方法,正确的事情将使方法表现为getter、setter和懒惰的初始值设定者
用法
class Dummy扩展了EnhancedObject{
公共名称;
公众年龄;
#复合吸气剂
公共函数getSummary(){
返回“{$this->name},过期的{$this->age}”;
}
#用于昂贵操作的缓存getter
公共函数loadStatusCount($id){
doExpensiveStuff();
返回42;
}
}
$d=新的虚拟对象();
$d->name=“约翰·多伊”
$d->年龄=35岁
#吸气剂
echo$d->summary;#回声“约翰·多伊,35岁”
#惰性初始化属性
echo$d->statusCount;#运行“doExpensiveStuff()”,回显42
echo$d->statusCount;#回声42
echo$d->statusCount;#回声42
要扩展注释,可以使用一个字段数组和一个小魔术方法来处理加载操作:
<?php
class Dummy
{
protected $fields = array(
'name' => null,
'age' => null,
'etc' => null
);
public function __get ($key) {
if (array_key_exists($key, $this->fields)) {
if ($this->fields[$key] === null) {
// do some kind of loading operation to set $value
$this->fields[$key] = $value;
}
return $this->fields[$key];
}
return null;
}
}
?>
您可以简单地删除它们并使用神奇的方法
比如:
class Dummy
{
public function __get($var_name)
{
switch ($var_name)
{
case 'name':
// lazy load here
return $val;
break;
case 'age':
// lazy load here
return $val;
break;
case 'number_of_status':
// lazy load here
return $val;
break;
}
}
}
使用\u get()
首先:这正是您应该使用getter/setter方法的原因。这样,您就可以在检索数据的过程中添加额外的逻辑
下面是一个如何使用_get()实现类似于公共成员的访问的示例:
使用与OP相同的示例,不能像protected/private那样延迟加载公共成员。有几个解决方法,就像上面提到的OP一样,使用getter方法来执行延迟加载逻辑\uu get()
不能与同一类的公共成员一起使用,因为直接访问成员意味着永远不会调用\uu get()
。将它们隐藏在数组中会使\uu get
或getter
方法起作用,但这基本上等同于将它们从公共可见性中移除,这显然是您试图避免的。正如我理解您的问题,您想知道是否可以重载公共变量
你已经知道了uuu get($name)魔法方法,对吧?或者您可能在谈论getName()、getAge()和*getStatus\u Indicator()*
在任何情况下,作为公共属性,您都不能使用神奇的方法
我将列出它们作为概念证明
例1
消耗的内存比
class x { protected $var1; protected $var2; }
甚至超过
class x { }
我已经通过构建数以百万计的对象和比较峰值内存使用情况对其进行了测试。我认为拥有这种“延迟加载属性”的编码风格并不好。如果需要一些延迟加载值,只需使用不带任何公共属性的get方法
但是我喜欢这个问题:)我也喜欢大多数解决方案,但我还想在这里添加我的通用解决方案:
类虚拟
{
私有$u名称;
私人年龄;
私人$号码\u的\u状态;
公共函数获取($name){
$var=“\”..$name;
$lazyLoadingMethod=“\u load”..$name;
如果(!method_存在($this$lazyLoadingMethod)){
触发器错误(“无法访问私有属性虚拟:$$name”,E\u USER\u错误);
返回;
}
如果(!isset($this->$var)){
$this->$var=$this->$lazyLoadingMethod();
}
返回$this->$var;
}
公共函数集($name,$value){
$var=“\”..$name;
$settingMethod=“\u set\u”。$name;
如果(!method_存在($this$settingMethod)){
触发器错误(“无法访问私有属性虚拟:$$name”,E\u USER\u错误);
}否则{
$this->$settingMethod($value);
}
}
公共职能部门
<?php
class Dummy {
public $name;
public $age;
public $status_indicator;
public function __construct() {
foreach($this AS $name => $value) {
$this->$name = new LazyLoader($this, $name);
}
}
}
class LazyLoader {
protected $object;
protected $name;
public function __construct($object, $name) {
$this->object = $object;
$this->name = $name;
}
public function load() {
/* find the necessary $data somehow */
$name = $this->name;
$this->object->$name = $data;
/*
after the first call to LazyLoader::load
the property no longer points to a LazyLoad
object, but to the intended value
*/
}
public function __toString() {
return($this->load());
}
}
?>
<?php
class LazyCollectionWrapper extends ArrayObject {
public function __construct($objects = array()) {
parent::__construct($objects);
}
public function offsetGet($offset) {
$this->collection[$offset]->lazyLoad();
return($this->collection[$offset]);
}
}
class Dummy {
public $name;
public $age;
public $status_indicator;
public function lazyLoad() {
/* load stuff here */
}
}
?>
<?php
class Dummy {
public function __get() {
/*
load stuff here because undefined
properties are caught by __get too
*/
}
}
?>
class x { protected $var1 = array(); protected $var2 = 0.0; }
class x { protected $var1; protected $var2; }
class x { }