PHP OOP访问方法的好习惯?

问题描述:

我有一些代码,往往是这样的:PHP OOP访问方法的好习惯?

private $user; 

public function __construct() 
{ 
    $this->user = User::getInstance(); //singleton 
} 

public function methodOne() 
{ 
    return $this->user->foo(); 
} 

public function methodTwo() 
{ 
    return $this->user->foo2(); 
} 

public function methodThree() 
{ 
    return $this->user->foo3(); 
} 

我想如果我设置的用户属性为实例,我可以在我的方法重新使用一个较短的名称(以及在这种情况下,这并不是说要短得多)。我也认为这样做可能会节省一些资源(开始怀疑它),但是当我查看其他人的代码时,我很少看到人们这样做。他们通常只会打电话:

User::getInstance()->foo(); 
User::getInstance()->foo2(); 
User::getInstance()->foo3(); 

有没有这种最佳实践?也许如果它不是单身课程,你可以这样做吗?或者,也许你不应该这样做?希望得到一些澄清,谢谢。

编辑: 柜面有什么误会,我只是想知道如果我应该创建一个属性实例存储VS这个第一个例子:

public function methodOne() 
{ 
    return User::getInstance()->foo(); 
} 

public function methodTwo() 
{ 
    return User::getInstance()->foo2(); 
} 

public function methodThree() 
{ 
    return User::getInstance()->foo3(); 
} 

其实,现在我想想这可能少代码,我不需要构造...

确实有一些问题,你的方法。

  • 目前还不清楚你的类是否依赖于User类。您可以通过将用户添加为构造函数参数来解决此问题。
  • 单身汉往往是不好的做法。你的代码演示了为什么:它是全局访问的,因此很难跟踪使用它的依赖关系(这指向了上述问题)。
  • 静态方法经常被用作全局接入点(作为对人们通常做User :: method()的回应)。全球接入点与单身人士一样存在相同的问题。他们也比较难测试。

我也没有看到用新对象重复User对象的要点,除非你使用例如适配器模式。也许如果你能澄清这一点,我将能够拿出一个比通用更好的替代:

class Foo { 
    public function __construct(User $user) { 
     $this->user = $user; 
    } 
    public function doXsimplified() { 
     $this->user->doXbutMoreComplex($arg1,$arg2, $arg20); 
    } 
} 
+0

+1中的“良好的操作规范”,对于很好的解释 – 2011-03-13 00:35:11

+0

编辑我的文章,我也创建包装,因为它与另一个应用程序集成,所以我不必重命名所有我的方法,如果我以后更改应用程序我也不确定我是否能够使用你展示的方法,因为我没有用户对象呢? – Joker 2011-03-13 01:16:45

+0

@Joker这是一个很好的使用包装。你的用户对象在包装对象出现的时候就开始起作用(因为它在那里是为了操纵第三方用户对象)。因此,如果您在创建用户对象之前或之后创建其他用户对象,则不会产生影响。 – koen 2011-03-13 14:30:02

我在PHP个人的偏好是使用类只对单身静态方法,所以你必须

User::foo(); 
User::bar(); 
+0

+1,短而甜。 – 2011-03-12 23:37:05

+0

可以用'__callStatic' – mario 2011-03-12 23:47:43

我不会创建一个新类只是环绕这样的单例。但是如果你的新课程增加了一些额外的逻辑,那么你的例子就是合理的记住,如果你担心你太冗长,你可以使用临时变量来进行连续的函数调用。

$user = User::getInstance(); 
$user->foo(); 
$user->bar(); 

但个人而言,我不再使用单身人士。相反,我使用依赖注入。我喜欢sfServiceContainer,但也有其他的。有一个在这个系列文章:http://fabien.potencier.org/article/11/what-is-dependency-injection

UPDATE

根据补充意见,这是我会怎么做:

class UserWrapper 
{ 
    private $user = null; 

    public function __construct($user) 
    { 
     $this->user = $user; 
    } 

    public function foo() 
    { 
     return $this->user->foo(); 
    } 

    ... 
} 

然后使用它是这样的:

$user = new UserWrapper(User::getInstance()); 

为什么?所以如果我想测试UserWrapper类,我可以传入一个伪造的User对象。 E.g:

class UserMock { ... } // A fake object that looks like a User 
$userTest = new UserWrapper(new UserMock()); 
+1

+1来实现,用于提及依赖注入。 – koen 2011-03-13 00:05:39

+0

是的,也会有一些额外的逻辑。这是一种与另一个应用程序集成,所以我包装用户类的方法,后来决定我改变应用程序,我不必重新命名一切。对于你显示的代码是的,我这样做,但只是想知道什么是最好的方法来使用,如果你只在每个方法中使用一次实例。编辑我的主要职位。 – Joker 2011-03-13 01:12:58

+0

如果你添加额外的逻辑,那么你的代码是好的。我唯一需要改变的不是在构造函数中获取User的实例,而是将其作为参数传递给构造函数(以方便依赖注入)。 – 2011-03-13 10:38:16

我通常是这样的,如果你已经列入某种或配置文件的引导类。我通常会在引导程序中删除$ user变量,这会在每次页面加载时调用,然后将其作为全局变量引用到其他php文件中,这就是我在引导程序文件中所要做的。

$user = new User(); 

那么这就是我会在调用PHP文件

global $user; 
$user->foo(); 
+0

我相信使用全局变量不是php – 2011-03-13 00:34:26