OOP最佳做法特别是PHP

问题描述

| 我已经在PHP中开发了一段时间,但直到最近才切换到OOP方法。 一直困扰着我的一个问题是OOP的东西“走多远”,特别是在执行速度和内存资源等方面。 例如,假设我有2个对象:用户和列表 列表始终链接到单个用户。 UserId是Listing的属性,因此我知道它与哪个用户相关。 偶尔,在Listing方法中,我需要访问相关User的单个属性。 据我所知(请告知如果没有的话),我有3种方法来实现此目的。 创建一个新的用户对象并通过$ user-> theProperty访问relevent属性 将必填属性设为清单的本地属性,并在初始化清单时(例如通过sql join)填充该属性 直接查询数据库以通过用户标识检索所需的用户属性 在我看来,选项1和2更加严格地遵循OOP规则,但是由于初始化整个对象只是为了检索1属性,因此性能受到了影响。选项3占用最少的内存,但完全避开了OOP。 另外,就在创建对象时填充对象而言,大多数对象在初始化后不久就通过一种“'fill'”方法填充了它们的大部分属性(因此仅需要1个DB查询)。通常认为这是最佳实践,还是更可取的是使用单个方法获取这些属性,并在需要时填充它们? 我意识到可能没有“正确”的答案,但是有人可以就解决这种情况的最佳方法提供建议吗? 非常感谢 缺口     

解决方法

        我绝对更喜欢选项1。选项2不遵循OOP的思想,因为用户信息不是您列表的一部分,因此请将其放在单独的对象中。 请记住以下规则: 一次加载没有关系的对象。 如果需要相关对象,则根据规则1在需要时加载它 许多ORM都以这种方式工作,例如,Doctrine(http://www.doctrine-project.org)。这就是所谓的延迟加载。 当您需要某个对象的一个​​属性时,您会发现自己正在加载同一对象的第二个属性,而且还需要一些行。在许多情况下,您会发现自己在一个完整脚本中仅针对一个对象执行了许多数据库查询。     ,        选项1是首选的OOP方法。 另外,在php中,您可以编写一个包装对象,该对象仅包含user_id和所需的属性。 当调用一个方法或访问其他属性时,您可以加载并初始化一个真实的用户对象。 这可以通过__get(),__set()和__call()方法来实现。 这样,您可以优化清单对象的查询和内存使用,同时在需要时可以从用户对象访问所有OOP优缺点。 代码应类似于以下内容:
class LazyObject {

  private 
    $propertySubset = array(),$realObject;


 function __call($method,$args) {
    if ($this->realObject === null) {
      $this->initRealObject();
    }
    return call_user_func_array(array($this->realObject,$method),$args);
  }

  // __get,__set and initRealObject implementation goes here
} 注意事项 您可以使用以下引用:
myMethod(&$ref)
$shortcut = &$object->prop
将不起作用 您需要手动检查包装纸是否填充了足够的属性。 没有足够的属性将导致查询分配,并且包装器只会减慢精简速度。 除非您在lazyObject中实现接口,否则将无法使用接口(例如ArrayAccess) PS。 这应该被视为优化技巧。因此,只有在性能成为问题时才实施此方法。     ,在急于选择选项#1之前,我建议您保持尝试将简单的对象模型应用于数据库中存储的数据可能会带来很多麻烦。 请阅读以下内容,以了解我要说的内容: \“为什么面向对象的数据库失败?” 您是否说过尼克,没有“正确”答案。但是我们可以这样说: 在OOP理想的良好实践中,$ listing对象应具有$ listing-> user属性,该属性是表示Listing \的User的对象。为了获得更好的性能,不应在实例化$ listing后立即实例化此User对象。在Java传统编码中,您将具有-> getUser()方法。在PHP中,您可以在调用-> user属性后立即实例化该对象。 但是,当您只需要一个属性时就检索完整的用户信息,这可能会浪费大量无用的数据流。如果您的代码打算一次处理大量的Listing对象,则尤其如此。 如果是这样,那么您就必须与理想的对象模型相距一点点,以便更接近您的业务流程。然后仅检索所需的用户属性,这可能是一个不错的折衷方案。例如:$ listing-> getUserProp1()。如果将来可能需要其他用户属性,则可以将方法更改为$ listing-> getUserProprty(\'prop1 \')。 但是,仅当您有时需要User属性时,此选项才有用。实际上,如果实际上每次有一个Listing对象时都需要它,那么最好将User属性与其他Listing属性一起初始化。这是您的选择2。这似乎是一个非常好的解决方案,因为您需要最小化数据流,并且如果您不需要Listing对象附近的其他用户信息。     ,        我相信您需要看一下数据传输对象的设计模式: http://en.wikipedia.org/wiki/Data_transfer_object 视图(页面)应接收数据传输对象,该对象不得与您的数据访问层使用的对象相同。 通过一些参数化,您的业务层可能会返回DTO,这些DTO具有由数据访问层返回的一组特定的一个或多个对象。 例如,如果要列出用户,则可能想知道他们的“组标识符”,“用户标识符”和“全名”。 用户组的标识符将来自某个组对象,而用户的标识符和全名将来自某个用户对象,最后,UserDto对象将具有用户和组对象的属性,这将是某些用户界面的属性视图需要显示用户列表。