如何动态创建新属性


74

如何从对象方法内的给定参数创建属性?

class Foo{

  public function createProperty($var_name, $val){
    // here how can I create a property named "$var_name"
    // that takes $val as value?

  }

}

我希望能够像这样访问该属性:

$object = new Foo();
$object->createProperty('hello', 'Hiiiiiiiiiiiiiiii');

echo $object->hello;

我是否有可能将财产设为公开/受保护/私有?我知道在这种情况下它应该是公共的,但是我可能想添加一些魔术方法来获取受保护的属性和东西:)


我想我找到了解决方案:

  protected $user_properties = array();

  public function createProperty($var_name, $val){
    $this->user_properties[$var_name] = $val;

  }

  public function __get($name){
    if(isset($this->user_properties[$name])
      return $this->user_properties[$name];

  }

您认为这是个好主意吗?

Answers:


108

有两种方法可以做到这一点。

一,您可以直接从类外部动态创建属性:

class Foo{

}

$foo = new Foo();
$foo->hello = 'Something';

或者,如果您希望通过您的createProperty方法创建属性:

class Foo{
    public function createProperty($name, $value){
        $this->{$name} = $value;
    }
}

$foo = new Foo();
$foo->createProperty('hello', 'something');

谢谢。我在课堂上需要它。解释起来有点复杂,属性实际上是对象,这些对象是站点管理员可以启用/禁用的站点扩展:)但是我将使用我的解决方案,我认为将它们保留在数组中会更好。
亚历克斯(Alex)

3
是否可以将它们设置为私有或受保护?
Marcio Mazzucato 2014年

3
我认为太阳是对的。该线$this->$name = $value;实际上应该是$this->name = $value;
Victor D.

14
还是$this->{$name} = $value;,不?
维克多

4
如果您想要一个动态属性名称(在这种情况下,我们想要hello属性),那么使用$this->{$name}istead of $this->namecause$this->name只会创建一个名称属性
ismnoiet 2015年

10

以下示例适用于那些不想声明整个类的人。

$test = (object) [];

$prop = 'hello';

$test->{$prop} = 'Hiiiiiiiiiiiiiiii';

echo $test->hello; // prints Hiiiiiiiiiiiiiiii

简单且完全动态的解决方案,就像这样。非常感谢
mili

8

属性重载非常慢。如果可以,请尝试避免这种情况。同样重要的是实现其他两种魔术方法:

__isset(); __unset();

如果您不想在以后使用这些对象“属性”时发现一些常见的错误

这里有些例子:

http://www.php.net/manual/zh-CN/language.oop5.overloading.php#language.oop5.overloading.members

亚历克斯评论后编辑:

您可以检查一下两种解决方案之间的时间差异(更改$ REPEAT_PLEASE)

<?php

 $REPEAT_PLEASE=500000;

class a {}

$time = time();

$a = new a();
for($i=0;$i<$REPEAT_PLEASE;$i++)
{
$a->data = 'hi';
$a->data = 'bye'.$a->data;
}

echo '"NORMAL" TIME: '.(time()-$time)."\n";

class b
{
        function __set($name,$value)
        {
                $this->d[$name] = $value;
        }

        function __get($name)
        {
                return $this->d[$name];
        }
}

$time=time();

$a = new b();
for($i=0;$i<$REPEAT_PLEASE;$i++)
{
$a->data = 'hi';
//echo $a->data;
$a->data = 'bye'.$a->data;
}

echo "TIME OVERLOADING: ".(time()-$time)."\n";

1
我有点迷上__get / __set / __call。在使用该类时,我实际上在每个类中都使用它们来获得漂亮的API ...到目前为止不需要__isset。您能否提供链接或某些与重载相关的基准?
亚历克斯(Alex)

对这个坏消息感到抱歉,但是__call的速度也很慢
Abraham Covelo 2012年

1
显示一些有关“属性超载缓慢”的参考/证据。
Pacerier,2014年

1
@Pacerier使用我在答案中输入的基准代码,并检查您自己的服务器中两种解决方案所花费的时间
Abraham Covelo 2015年

6

使用语法:$ object-> {$ property},其中$ property是字符串变量,如果$ object在类或任何实例对象中,则$ object可以是此变量

实时示例:http//sandbox.onlinephpfunctions.com/code/108f0ca2bef5cf4af8225d6a6ff11dfd0741757f

 class Test{
    public function createProperty($propertyName, $propertyValue){
        $this->{$propertyName} = $propertyValue;
    }
}

$test = new Test();
$test->createProperty('property1', '50');
echo $test->property1;

结果:50


1
这就是我一直在寻找的答案,我已经很新了,您可以只引用以前未声明过的对象中的属性... $ object-> example =“ hello”; 我在如何动态地将属性添加到对象的同时还动态地指定了要调用该属性的内容。
andmar8 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.