存储PHP类属性的最佳方法是什么?

时间:2022-04-02 22:45:03

Duplicate of: What's the best way to store class variables in PHP?

重复:在PHP中存储类变量的最佳方法是什么?

For some time I've been having this discussion with a co-worker on how should you store attributes within a PHP class.

有一段时间以来,我一直在与同事讨论如何在PHP类中存储属性。

So which one do you think it should be used. Something like this:

那么你认为应该使用哪一个。像这样的东西:

Class test{
    public $attr1;
    public $attr2;
    .............. 
    public function __construct(){
        $this->attr1 = val;  
        $this->attr1 = val;
        ...................   
    }
}

Versus:

Class test{
    public $data;

    public function __construct(){
        $this->data['attr1'] = val;
        $this->data['attr2'] = val;
        ..........................       
    }
}

This is important when you have objects with many attributes that have to be stored and retrieved within often.

当您拥有必须经常存储和检索的许多属性的对象时,这一点很重要。

Also important when dealing with objects with many attributes, do you use getters and setters for each attribute or rather one method to set all and one method to get all ?

在处理具有许多属性的对象时,同样重要的是,您是为每个属性使用getter和setter还是使用一个方法来设置all和one方法来获取所有属性?

8 个解决方案

#1


Version 1 is the more "classical" way of doing things. Your object is pretty much exactly as you say it is.

版本1是更“经典”的做事方式。你的对象与你说的完全一样。

I can't say which is strictly "better", but I can say which I find more convenient.

我不能说哪个是严格“更好”,但我可以说哪个更方便。

I've used the second version (usually for database models in CodeIgniter, and particularly during early development) in combination with custom PHP5 getter and setter methods to allow you to overload the class dynamically. i.e.

我已经使用第二个版本(通常用于CodeIgniter中的数据库模型,特别是在早期开发期间)与自定义PHP5 getter和setter方法结合使用,以允许您动态地重载类。即

<?php
    class foo{
        private $data = array();

        function __construct()
        {
            # code...
        }

        public function __get($member) {
            if (isset($this->data[$member])) {
                return $this->data[$member];
            }
        }

        public function __set($member, $value) {
            // The ID of the dataset is read-only
            if ($member == "id") {
                return;
            }
            if (isset($this->data[$member])) {
                $this->data[$member] = $value;
            }
        }
    }

    $bar = new foo()
    $bar->propertyDoesntExist = "this is a test";
    echo $bar->propertyDoesntExist; //outputs "this is a test"
?>

#2


I'd use second version if and only if the data comes as a whole from external source (e.g. BD query). In that case of course it'll be recommendable to have generic __get()/__set() to access $this->data. You might also consider implementing IteratorAggregate interface returning new ArrayIterator($this->data).

当且仅当数据来自外部源(例如BD查询)时,我才使用第二个版本。在这种情况下,当然建议使用泛型__get()/ __ set()来访问$ this-> data。您还可以考虑实现IteratorAggregate接口,返回新的ArrayIterator($ this-> data)。

#3


Unless there are really convincing arguments for either version (depnding on the context) I always chose the format the lets my ide/tools provide better information about the types, classes, relationships, ... and until now that's the first format.
There are other ways to access the data "array-like".

除非两个版本都有令人信服的论据(在上下文中展开),否则我总是选择格式,让我的ide / tools提供有关类型,类,关系等的更好信息......直到现在,这是第一种格式。还有其他方法可以访问“类似数组”的数据。

#4


The first method is pretty much standard. It clearly defines what the properties are, and allows IDEs and code documentation tools to pick up on available object properties.

第一种方法非常标准。它清楚地定义了属性,并允许IDE和代码文档工具获取可用的对象属性。

The second method is great for protected and private level properties in which you need to keep the data in a separate scope. I use a combination of both approaches in various model classes, or to track configuration options and defaults. I would always pre-fill these arrays, however, and ensure strict adherence to the data within.

第二种方法非常适用于需要将数据保存在单独范围内的受保护和私有级属性。我在各种模型类中使用这两种方法的组合,或跟踪配置选项和默认值。但是,我总是预先填充这些数组,并确保严格遵守其中的数据。

I would not ever advocate using the second method for a public property, as it demonstrates a lack of understanding of object properties and variable scope, and can introduce problems in the code (what if someone overwrites that root array with a string?)

我不会主张将第二种方法用于公共属性,因为它表明缺乏对对象属性和变量范围的理解,并且可能在代码中引入问题(如果有人用字符串覆盖那个根数组会怎么样?)

The use of getters and setters makes since on the properties that need to be changeable to the calling code. Not every property should be accessible, so it's up to the developer defining the object. The getter/setter pattern doesn't make sense with public properties, obviously, but it does with protected and private properties which may need some validation or to be sanitized. They also make sense in context of dependency injection.

使用getter和setter会使得需要可以更改为调用代码的属性。并非每个属性都可以访问,因此由开发人员定义对象。显然,getter / setter模式对公共属性没有意义,但它与受保护和私有属性有关,可能需要进行一些验证或进行清理。它们在依赖注入的上下文中也有意义。

#5


personally i use version 1, because i think it is more correct, supports auto-completion in IDEs and makes debugging easier.

我个人使用版本1,因为我认为它更正确,支持在IDE中自动完成并使调试更容易。

i also use getters and setters for almost all of my member variables (which i define private/protected most of the time), because setting one value triggers changes in other values very often. one downside of creating g&s is the vast amount of ugly, stupid code that accumulates over time, if you define getters/setters even for attributes that do not trigger changes elsewhere. i still do it for the consistent interface - i never know when i introduce additional functionality or bugfixes that introduce more changes-on-set.

我还为几乎所有的成员变量使用getter和setter(我在大多数时间定义private / protected),因为设置一个值会经常触发其他值的更改。创建g&s的一个缺点是,如果你定义getter / setter,即使是那些不会在其他地方触发更改的属性,也会随着时间的推移积累大量丑陋,愚蠢的代码。我仍然为一致的界面做这件事 - 我永远不知道什么时候我会引入额外的功能或错误修正,引入更多的设置更改。

#6


I would prefer version 1, too. If you do not need dynamic members (the version Chris provided), you should define your members. The dynamic way leads in most cases to a horrible construct that makes it hard to understand your code. Imagine, that somebody might need to debug your code and does not know your code ^^. We have a larger project that uses dynamic members to mirror the fields in the db table. Its pretty hard to use without knowing the table.

我也更喜欢版本1。如果您不需要动态成员(Chris提供的版本),您应该定义您的成员。在大多数情况下,动态方式导致一个可怕的构造,使得难以理解您的代码。想象一下,有人可能需要调试你的代码并且不知道你的代码^^。我们有一个更大的项目,它使用动态成员来镜像db表中的字段。在不知道桌子的情况下很难使用它。

Beside the fact, that your IDE doesn't work with dyn. members, you cannot use PHPDoc for those members AND PHPUnit cannot use Reflection on those attributes. Thats simply bad coding style.

除此之外,您的IDE无法使用dyn。成员,你不能将PHPDoc用于那些成员而PHPUnit不能对这些属性使用Reflection。这简直是​​糟糕的编码风格。

Regards, Mario

#7


The reason to use version 1 is that version 2 takes place within the object. Your object is already a map of varnames to values. By adding your own arraymap you are adding a needless level of indirection.

使用版本1的原因是版本2发生在对象中。您的对象已经是值的值的映射。通过添加自己的数组映射,您将添加一个不必要的间接级别。

#8


The best method is for sure the standard one but second one is for sure more comfortable....

最好的方法是确保标准的,但第二个肯定更舒适....

Me I use the first one and I use this function inside the class to work dinamically:

我使用第一个,我在课堂上使用这个函数来动态地工作:

    public function GET__Attributes_in_Array(){
     $Prova = get_class_vars(get_class($this));
     print_r($Prova);

     return $Prova;
}

This function return you an array with all the attributes and value of a class...

这个函数返回一个包含类的所有属性和值的数组......

#1


Version 1 is the more "classical" way of doing things. Your object is pretty much exactly as you say it is.

版本1是更“经典”的做事方式。你的对象与你说的完全一样。

I can't say which is strictly "better", but I can say which I find more convenient.

我不能说哪个是严格“更好”,但我可以说哪个更方便。

I've used the second version (usually for database models in CodeIgniter, and particularly during early development) in combination with custom PHP5 getter and setter methods to allow you to overload the class dynamically. i.e.

我已经使用第二个版本(通常用于CodeIgniter中的数据库模型,特别是在早期开发期间)与自定义PHP5 getter和setter方法结合使用,以允许您动态地重载类。即

<?php
    class foo{
        private $data = array();

        function __construct()
        {
            # code...
        }

        public function __get($member) {
            if (isset($this->data[$member])) {
                return $this->data[$member];
            }
        }

        public function __set($member, $value) {
            // The ID of the dataset is read-only
            if ($member == "id") {
                return;
            }
            if (isset($this->data[$member])) {
                $this->data[$member] = $value;
            }
        }
    }

    $bar = new foo()
    $bar->propertyDoesntExist = "this is a test";
    echo $bar->propertyDoesntExist; //outputs "this is a test"
?>

#2


I'd use second version if and only if the data comes as a whole from external source (e.g. BD query). In that case of course it'll be recommendable to have generic __get()/__set() to access $this->data. You might also consider implementing IteratorAggregate interface returning new ArrayIterator($this->data).

当且仅当数据来自外部源(例如BD查询)时,我才使用第二个版本。在这种情况下,当然建议使用泛型__get()/ __ set()来访问$ this-> data。您还可以考虑实现IteratorAggregate接口,返回新的ArrayIterator($ this-> data)。

#3


Unless there are really convincing arguments for either version (depnding on the context) I always chose the format the lets my ide/tools provide better information about the types, classes, relationships, ... and until now that's the first format.
There are other ways to access the data "array-like".

除非两个版本都有令人信服的论据(在上下文中展开),否则我总是选择格式,让我的ide / tools提供有关类型,类,关系等的更好信息......直到现在,这是第一种格式。还有其他方法可以访问“类似数组”的数据。

#4


The first method is pretty much standard. It clearly defines what the properties are, and allows IDEs and code documentation tools to pick up on available object properties.

第一种方法非常标准。它清楚地定义了属性,并允许IDE和代码文档工具获取可用的对象属性。

The second method is great for protected and private level properties in which you need to keep the data in a separate scope. I use a combination of both approaches in various model classes, or to track configuration options and defaults. I would always pre-fill these arrays, however, and ensure strict adherence to the data within.

第二种方法非常适用于需要将数据保存在单独范围内的受保护和私有级属性。我在各种模型类中使用这两种方法的组合,或跟踪配置选项和默认值。但是,我总是预先填充这些数组,并确保严格遵守其中的数据。

I would not ever advocate using the second method for a public property, as it demonstrates a lack of understanding of object properties and variable scope, and can introduce problems in the code (what if someone overwrites that root array with a string?)

我不会主张将第二种方法用于公共属性,因为它表明缺乏对对象属性和变量范围的理解,并且可能在代码中引入问题(如果有人用字符串覆盖那个根数组会怎么样?)

The use of getters and setters makes since on the properties that need to be changeable to the calling code. Not every property should be accessible, so it's up to the developer defining the object. The getter/setter pattern doesn't make sense with public properties, obviously, but it does with protected and private properties which may need some validation or to be sanitized. They also make sense in context of dependency injection.

使用getter和setter会使得需要可以更改为调用代码的属性。并非每个属性都可以访问,因此由开发人员定义对象。显然,getter / setter模式对公共属性没有意义,但它与受保护和私有属性有关,可能需要进行一些验证或进行清理。它们在依赖注入的上下文中也有意义。

#5


personally i use version 1, because i think it is more correct, supports auto-completion in IDEs and makes debugging easier.

我个人使用版本1,因为我认为它更正确,支持在IDE中自动完成并使调试更容易。

i also use getters and setters for almost all of my member variables (which i define private/protected most of the time), because setting one value triggers changes in other values very often. one downside of creating g&s is the vast amount of ugly, stupid code that accumulates over time, if you define getters/setters even for attributes that do not trigger changes elsewhere. i still do it for the consistent interface - i never know when i introduce additional functionality or bugfixes that introduce more changes-on-set.

我还为几乎所有的成员变量使用getter和setter(我在大多数时间定义private / protected),因为设置一个值会经常触发其他值的更改。创建g&s的一个缺点是,如果你定义getter / setter,即使是那些不会在其他地方触发更改的属性,也会随着时间的推移积累大量丑陋,愚蠢的代码。我仍然为一致的界面做这件事 - 我永远不知道什么时候我会引入额外的功能或错误修正,引入更多的设置更改。

#6


I would prefer version 1, too. If you do not need dynamic members (the version Chris provided), you should define your members. The dynamic way leads in most cases to a horrible construct that makes it hard to understand your code. Imagine, that somebody might need to debug your code and does not know your code ^^. We have a larger project that uses dynamic members to mirror the fields in the db table. Its pretty hard to use without knowing the table.

我也更喜欢版本1。如果您不需要动态成员(Chris提供的版本),您应该定义您的成员。在大多数情况下,动态方式导致一个可怕的构造,使得难以理解您的代码。想象一下,有人可能需要调试你的代码并且不知道你的代码^^。我们有一个更大的项目,它使用动态成员来镜像db表中的字段。在不知道桌子的情况下很难使用它。

Beside the fact, that your IDE doesn't work with dyn. members, you cannot use PHPDoc for those members AND PHPUnit cannot use Reflection on those attributes. Thats simply bad coding style.

除此之外,您的IDE无法使用dyn。成员,你不能将PHPDoc用于那些成员而PHPUnit不能对这些属性使用Reflection。这简直是​​糟糕的编码风格。

Regards, Mario

#7


The reason to use version 1 is that version 2 takes place within the object. Your object is already a map of varnames to values. By adding your own arraymap you are adding a needless level of indirection.

使用版本1的原因是版本2发生在对象中。您的对象已经是值的值的映射。通过添加自己的数组映射,您将添加一个不必要的间接级别。

#8


The best method is for sure the standard one but second one is for sure more comfortable....

最好的方法是确保标准的,但第二个肯定更舒适....

Me I use the first one and I use this function inside the class to work dinamically:

我使用第一个,我在课堂上使用这个函数来动态地工作:

    public function GET__Attributes_in_Array(){
     $Prova = get_class_vars(get_class($this));
     print_r($Prova);

     return $Prova;
}

This function return you an array with all the attributes and value of a class...

这个函数返回一个包含类的所有属性和值的数组......