我正在尝试在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是其中三个最差的流行框架。