5

用 PHP 编写我的第一个使用类和对象的应用程序。我有一个 DB 类,它需要一个字符串来选择适当的配置,因为有多个数据库。我从一个登录类开始,但为了换取一个用户类而放弃了这个想法,所以我可以做 user->isLoggedIn 的东西。用户类使用 MySQL,它存储用户和登录信息,以及第二个数据库的凭据。

$mysql = new db( 'mysql' );

$user = new user( $mysql );
if( !( $user->isLoggedIn() === true ) )
{
    goToPage( 'login.php' );
    exit();
}

第二个数据库是 Sybase,用于存储帐户信息。我需要来自用户类的凭据才能从此处获取列表和帐户信息。我认为应该是下一个帐户课程,但不确定最好的方法。像这样的东西也许..

$sybase = new db( 'sybase' );

$account = new account( $sybase );

$account_list = $account->getList( $user->info );

$user->info 是一个数组,我猜测帐户表所需的凭据和信息,还是有更好的方法来解决这个问题?

编辑以包含 db 类示例

配置.db.php

$config_array = array();

$config_array[ 'mysql' ][ 'dsn' ] = "mysql:host=localhost;dbname=********;charset=UTF-8";
$config_array[ 'mysql' ][ 'user' ] = "********";
$config_array[ 'mysql' ][ 'pass' ] = "**************";

$config_array[ 'sybase' ][ 'dsn' ] = "odbc:DRIVER={Adaptive Server Anywhere 8.0};***************";
$config_array[ 'sybase' ][ 'user' ] = "**********";
$config_array[ 'sybase' ][ 'pass' ] = "*********";

类.db.php

public function __construct( $type )
{
    require 'config.db.php';

    $this->type = $type;

    foreach( $config_array[ $this->type ] AS $key => $value )
    {
        $this->$key = $value;
    }

    try
    {
        $this->connection = new PDO( $this->dsn, $this->user, $this->pass, $this->options );
    }
    catch( PDOException $ex )
    {
        log_action( "db->" . $this->type, $ex->getCode() . ": " . $ex->getMessage() );
        $this->error = true;
    }
    return $this->connection;
}

像下面这样的东西有意义吗?

class User()
{
    public function getAccountList()
    {
        $this->Account = new Account( new Database( 'sybase' ) );
        return $this->Account->list( $this->userid );
    }
}

此外,账户有不同的部分(即历史和注释、财务交易、文档),它们将在页面上成为不同的“标签”。每一个都应该是一个类吗?

4

2 回答 2

2

首先,作为Dimitry另一个答案的次要答案:

拥有单身人士所获得的东西与你失去的东西相比相形见绌。你得到一个全局对象,程序的每个部分都可以读取和修改它,但是你失去了可测试性、可读性和可维护性。

因为 Singleton 对象实际上是全局的,所以您无法准确地隔离应用程序中的单个单元(这对于单元测试至关重要),因为您的函数依赖于“神奇地”插入其中的其他组件。

你失去了可读性,因为method()实际上可能需要其他东西才能工作(例如,user对象需要一个db实例,这new user($db)比 更具可读性new user(),因为即使不查看源代码,我也可以知道方法/对象需要什么工作。

由于上述原因,您也会失去可维护性。与在函数的“合同”中看到它相比,通过 Singleton 插入哪些组件更难,因此,将来您和/或任何其他开发人员将更难阅读和重构您的代码。


附带说明一下,将名称的首字母大写被认为是一种很好的命名约定,Class从现在开始我将使用此约定。

让我们从顶部开始。您的Db对象有 2 种可能的状态MysqlDb, 和SybaseDb。这需要多态性。您有一个抽象Db和两个具体MysqlDbSybaseDb从它继承。正确的 Db 对象的实例化是工厂的责任

class DbFactory {

    private $db;

    /**
     * Create a new Db object base on Type, and pass parameters to it.
     *
     * @param string $type Type of database, Mysql or Sybase.
     * @param string $dsn  The DSN string corresponding to the type.
     * @param string $user User credential
     * @param string $pass Password credential
     *
     * @return Db
     */

    public function create($type, $dsn, $user, $pass) {
        if (!is_a($this->db, "Db")) {
            $type     = $type . "Db";
            $this->db = new $type($dsn, $user, $pass);
        }

        return $this->db;
    }
}

abstract class Db {

    /**
     * @param $dsn
     * @param $user
     * @param $pass
     */
    public function __construct($dsn, $user, $pass) {
        $this->db = new PDO("$dsn", $user, $pass);
        $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $this->db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    }
}

class MysqlDb extends Db {

    /*
     * More specific, Mysql only implementation goes here
     */
}

class SybaseDb extends Db {

    /*
     * More specific, Sybase only implementation goes here
     */
}

现在您应该问自己,谁负责获取帐户列表?当然,他们不应该自己获取(就像从数据库中获取自己的数据不是用户的责任一样)。使用连接User获取这些帐户是's 的责任。SybaseDb

实际上,User需要以下工作:

  • Sybase 数据库连接 -获取帐户列表。我们将DbFactory实例传递给它,这样如果它已经实例化,我们可以很容易地获取实例,如果没有实例化它。
  • 状态信息(登录状态、用户 ID、用户名等)。

User不负责设置此数据,它需要它才能工作。

所以User构造函数应该是这样的(假设“ID”和“name”字段):

User::__construct($id, $name, DbFactory $factory);

User有一个字段$accounts,该字段将保存一个对象数组Account。该数组将填充一个User::getAccounts()方法。

于 2012-11-02T20:48:38.213 回答
-1

我会让 Account 成为 User 类的成员。“用户一个帐户”,对吧?

另外,谈到课程,请确保您的两个数据库是单音的,并通过getInstance()而不是__construct().

于 2012-11-02T12:16:39.510 回答