如何使用traits将大类中的代码拆分成几个文件?

djf*_*jfm 6 php traits

来自Ruby,我很高兴发现PHP的特性.它们类似于ruby的模块系统,我喜欢它.

现在我已经阅读了很多帖子,说PHP特性是邪恶的,因为它们打破了OO设计,你不能像上课一样容易地测试它们等等.

我想知道是否使用特征将一个非常大的类分成更易读的部分是一个好主意.

这个类已经很大了,很可能会在没有重新分解的情况下长达数千行.

尽管方法可以按照关注进行分组,但它们经常需要相互调用,这让我想知道将类拆分为不同的类是否是最佳的.

为了说明,这是我提出的一个简化示例.

大班:

/**
* Class to refactorize
*/

class Tourist
{
    public function gotoRestaurant()
    {

    }

    public function gotoInternetCafe()
    {

    }

    public function checkEmails()
    {

    }

    public function meetGirlfriend()
    {
        if (Girlfriend::location() === 'restaurant')
        {
            $this->gotoRestaurant();
        }
        else
        {
            $this->checkEmails();
        }
    }

    public function checkEmailsAndMeetGirlfriend()
    {
        $this->checkEmails();
        $this->meetGirlfriend();
    }
}
Run Code Online (Sandbox Code Playgroud)

如果对类进行重新分解,我会这样做:

/**
* Solution 1: using classes
*/

class ChoreDoer
{
    public function __construct(Tourist $t)
    {
        $this->tourist = $t;
    }

    public function checkEmails()
    {
        $mover = new Mover($this->tourist);
        $mover->gotoInternetCafe();
    }

    public function meetGirlfriend()
    {
        if (Girlfriend::location() === 'restaurant')
        {
            $mover = new Mover($this->tourist);
            $mover->gotoRestaurant();
        }
        else
        {
            $this->checkEmails();
        }
    }
}

class Mover
{
    public function __construct(Tourist $t)
    {
        $this->tourist = $t;
    }

    public function gotoRestaurant()
    {

    }

    public function gotoInternetCafe()
    {

    }
}

class Tourist
{
    public function checkEmailsAndMeetGirlfriend()
    {
        $cd = new ChoreDoer($this)
        $cd->checkEmails();
        $cd->meetGirlfriend();

    }
}
Run Code Online (Sandbox Code Playgroud)

我有一种感觉叫不停new Mover(),new ChoreDoer()和将出现新的类将成为痛苦的读取和写入.

那么在这里使用特征分组功能呢?

/**
* Solution 2: using traits
*/

trait TouristMovements
{
    public function gotoRestaurant()
    {

    }

    public function gotoInternetCafe()
    {

    }
}

trait TouristChores
{
    public function meetGirlfriend()
    {
        if (Girlfriend::location() === 'restaurant')
        {
            $this->gotoRestaurant();
        }
        else
        {
            $this->checkEmails();
        }
    }

    public function checkEmails()
    {
        $this->gotoInternetCafe();
    }
}

class Tourist
{
    use TouristMovements, TouristChores;
    public function checkEmailsAndMeetGirlfriend()
    {
        $this->checkEmails();
        $this->meetGirlfriend();
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,每个特征都可以专注于它的目的,代码易于阅读,方法可以自由地互操作.但是,由于我从不打算TouristsMovements在任何课程中使用这种特性Tourist,我觉得我对它们的使用并不是真正的特性.

你会选择解决方案1吗?解决方案2?别的什么?

Kyr*_*yro 2

作为替代方案,您可以使用“解决方案 1”执行类似的操作:

class ChoreDoer
{
    private $mover;

    public function __construct(Tourist $t)
    {
        $this->tourist = $t;
    }

    public function checkEmails()
    {
        $this->getMover()->gotoInternetCafe();
    }

    public function meetGirlfriend()
    {
        if (Girlfriend::location() === 'restaurant')
        {
            $this->getMover()->gotoRestaurant();
        }else
        {
            $this->checkEmails();

        }
    }
    /**
     * lazy-load mover object
     */
    private function getMover()
    {
        if($this->mover == null)
        {
            $this->mover = new Mover($this->tourist);
        }
        return $this->mover;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您不喜欢使用 getter,您可以将您的属性命名为类似

private $_mover;
Run Code Online (Sandbox Code Playgroud)

并使用神奇的 __get 为您调用 getter:

function __get($property)
{
    $method = 'get'.ucfirst($property);
    if(method_exists($method))
    {
        return $this->$method();
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然这不会表现得那么好,但它可以很容易地调用

$this->mover->gotoInternetCafe();
Run Code Online (Sandbox Code Playgroud)

而且又漂亮又干净。