我正在尝试在php中创建一个类,以便在我的webbapplication中建立房屋。我不知道我是否以最有效的方式使用类和对象,对吗?我是新来的...

这是来自jquery的请求,要求用户要盖房子:

// Add house
$.get('stats.php?house=cottage', function(data){
    // if(data == 1) // Build a house
});


这是stats.php文件,

require_once('House.php');
// Requests to see if the requirements to build a new building is met, if so, return 1, else return 0.
if(isset($_GET['house'])) {
    // Check with database to se if there is enough resources.
    $house = new House;
    $house->type = $_GET['house'];
    if($house->isResources) {
        $house->buildHouse;
        echo 1; // This is the answer to the ajax request.
    } else {
        echo 0;
    }
}


这是我的课程文件:

<?php
class Build {

    public $type;

    function isResources() {
        // Check resourses in database, compare that to the number of houses already built, and level.
        // return true; // If requirements are met, otherwise return false.
    }

    function buildHouse() {
        // Insert coordinates and $type into databse.
    }
}
?>


除了上面的代码之外,我还没有在类中完成任何代码,我只是想知道这是否是创建类的最佳方法。在我继续编码之前,谢谢!

最佳答案

我看到的一些问题与您提供的有限代码有关。

您的House类具有公共成员type,这意味着在对象生命周期中的任意时刻(House的实例),您都可以更改type。这使您的代码不仅难以测试,而且难以维护。因为不能真正信任类型的值(因为可以随时更改它)。因此,我要做的第一件事就是将该属性设置为private。并使用类的构造函数设置属性。

我注意到的第二件事是isResources方法,该方法显然对数据库有作用。但是我看不到任何数据库连接被传入。无论是在构造函数中还是在方法中都没有。这是非常可疑的,因为这意味着可以通过以下任一方式访问数据库连接:


在方法内部创建一个新的连接
在方法内部使用某种形式的全局变量


两者都有问题:

在方法内部创建一个新的连接

这意味着您将数据库连接紧密地耦合到House类,而没有简单(明智)的方式来对House进行单元测试。因为无法将数据库连接与其他连接交换。甚至是完全其他形式的存储。或一些模拟存储。

同样,此方法将意味着您将在整个应用程序中拥有许多数据库连接,因为您将在需要它的每个类/方法中创建一个新连接。

同样,通过查看实际上在其中使用数据库连接的方法签名,也看不到任何方法。这称为隐藏依赖关系,应尽可能避免使用。

在方法中使用一些全局变量

对于大多数观点,这提出了与上述方法完全相同的问题。应不惜一切代价避免全球化和全球化国家。无论您是直接使用global关键字,还是访问$_GLOBALS数组还是使用单例模式。在维护和可测试性方面都存在相同的问题。

我早些时候已经在另一篇文章中写下了原因,缺点和解决方案:Use global variables in a class

我在isResources方法中注意到的另一件事是,它基于注释检查可用资源。现在,让这个例子进入现实生活。当您要在现实生活中建造房屋时,您是否真的要求(或检查)房屋本身以查看是否有足够的资源来建造房屋?不,你不会。这违反了Single Responsibility Principle,只是没有多大意义(向房子询问是否有资源来建造房子)。

我看到您的课程也有一个buildHouse方法,这也很奇怪。使用构造函数构造(构建)对象。没有理由使用该方法。您应该将所有信息(房屋元素)传递给构造函数。

借助我上面提供的信息(我可能会告诉您更多信息),您最终会得到以下内容:

<?php
class Factory
{
    private $resources;

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

    public function build($type, array $coordinates)
    {
        if (!$this->resources->areAvailable()) {
            throw new \UnavailableResourcesException('Not enough resources to build the house');
        }

        return new House($type, array $coordinates);
    }
}

class Resources
{
    private $dbConnection;

    public function __construct(\PDO $dbConnection)
    {
        $this->dbConnection = $dbConnection;
    }

    public function areAvailable()
    {
        // check database for resources
        return true;
    }
}

class House
{
    private $type;

    private $coordinates;

    public function __construct($type, array $coordinates)
    {
        $this->type        = $type;
        $this->coordinates = $coordinates;
    }
}

$dbConnection = new PDO('mysql:dbname=yourdatabase;host=127.0.0.1;charset=utf8', 'user', 'pass');
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$resources = new Resources($dbConnection);
$factory = new Factory($resources);

$myHouse = $factory->build('tipi', array(22, 13));


请注意,在我上面的示例代码中仍然可以进行足够的改进,但这只是给您一个入门的想法。

另请注意,Stack Overflowers同事向您提供的有关检查Yii,Cake或CI的建议是可怕的恕我直言。因为那些框架实际上根本没有教授好的OOP做法。例如,Yii充满了static方法,这基本上意味着您的应用程序充满了全局状态。从任何定义来看,Cake都不是面向对象的。还要注意,(再次恕我直言)Yii,CI和Cake是其中三个最差的流行框架。

10-08 13:34
查看更多