0

ばかげた質問で申し訳ありませんが、phpでおっとするのは初心者です...私はmysqliクラスを作成する問題があり、他のクラス/メソッドの接続ハンドラーを有効にする接続ハンドラーを返します。私は小さな手続き型ブログを運営しています。nはoopに変換したかったのです。これが私の動作するコード例です。必要に応じてリファクタリングしてください。少し早いですがお礼を。

$db_link = mysqli_connect(DB,HOST,DB_USER,DB,PASS,DB_NAME) or die(mysql_error());
class myDB extends mysqli
{
  public function getConfig($id, $db_link) // thanks cbuckley
 {
   $db_link = $this->db_link;
   $res = mysqli_query($this->db_link,"SELECT * from config where id='1'");
   $row = mysqli_fetch_array($res);
   return $row['option'];
  }    
}

定数をすでに定義していて、接続は成功していますが、選択が機能していません。インデックスページでは、これは

include('inc/dbc.php'); 
$db = new MyDB(); 
echo $db->getConfig(1, $db_link);  

助けていただければ幸いです

4

3 に答える 3

6

あなたの質問はあまり具体的ではなく、あなたの具体的な問題が何であるかをあなたは本当に知らないと感じています。あなたはすでにあなたにいくつかのコードを与える答えを受け入れましたが、それはあなたの根本的な問題を解決せず、コードを浪費するのであなたを間違った方向に導きます。

PHPのmysqli拡張機能のオブジェクト指向インターフェースを利用して利益を得る場合に最初に知っておくべきことは、Mysqliクラスがデータベース接続(手続き型アプローチにちなんで名付けられた「リンク」)をすでに表していることです。

require('inc/dbc.php');

$dbConnection = new Mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);

もう終わりです。確かに、ここでエラー処理を使用することをお勧めします。

if ($dbConnection->connect_error)
{
    throw new Exception(
       sprintf('(#%d) %s', $dbConnection->connect_errorno,
                $dbConnection->connect_error)
    );
}

例外ハンドラーを簡単に作成できるため、例外をスローするのではなくdie('message')、例外をスローします。これにより、例外ハンドラーを簡単に作成できるため、例外的なエラーケースが発生するたびに(実際にはその場所で)処理するのではなく、中央の場所からユーザーに対してより有用な応答を表示できます。どこdieになりますか)。

バックトレースをログに記録してメールで送信することもできるため、問題をより簡単に修正できます。当然、例外を使用する必要はありませんが、経験則では、dieたとえば1週間で破棄するスクリプトでのみ使用することであり、オブジェクト指向設計ではうまく機能しません。

データベース接続が必要になるすべての場所でこのコードが必要になるため、独自の接続オブジェクトを作成して、これらのパーツが一緒に属しているときにそれらをまとめることができます。

class DatabaseException extends Exception
{
}

class DatabaseConnection extends Mysqli
{
    public function __construct($host, $user, $password, $database = "", $port = NULL, $socket = NULL) {

        parent::__construct($host, $user, $password, $database, $port, $socket);

        $this->throwConnectionExceptionOnConnectionError();
    }

    private function throwConnectionExceptionOnConnectionError() {

        if (!$this->connect_error) return;

        $message = sprintf('(%s) %s', $this->connect_errno, $this->connect_error);

        throw new DatabaseException($message);
    }
}

使用法は実際には非常に単純で、ほとんど同じです。クラスの名前だけが異なり、その定義をロードする必要があります。

require('inc/dbc.php');
require('inc/database.php');

$dbConnection = new DatabaseConnection(DB_HOST, DB_USER, DB_PASS, DB_NAME);

記述されているように、接続オブジェクトはすでにデータベース接続を表しています。したがって、それを必要とするアプリケーションのすべての部分は、それを要求する必要があります。サンプル関数を確認してみましょう。

function getOption($id, $db_link)
{
   // $db_link = $this->db_link;
   $res = mysqli_query($this->db_link,"SELECT * from config where id='1'");
   $row = mysqli_fetch_array($res);
   return $row['option'];
}

関数の名前を変更し、最初の行にコメントを付けました。これでも必要な場合があります。実際、その関数がオブジェクトの一部である場合、次のように機能する可能性があります。DatabaseConnection

class DatabaseConnection extends Mysqli
{
    ...

    public function getOption($id) {
        $statement = $this->prepare('SELECT `option` FROM config WHERE id=?');
        $statement->bind_param('i', $id);
        $statement->execute();
        $statement->bind_result($option);
        $statement->fetch();
        $statement->close();
        return $option;
    }

この例が示すように、データベース接続はすでに存在しています。ただし、これはお勧めできません。あなたが選択肢を持っているだけでなく、これとあれとそのようなものとそれ以上のものを持っていると想像してください。1つのクラスで次々に関数を作成します。うまく機能するかもしれない小さなアプリケーションには適していますが、ますます想像してみてください。あなたは多くのことを担当する1つの非常に大きなクラスを得るでしょう。$thisしたがって、ステートメントの準備にすでに使用できる場合でも、これを行うのは悪いことです。

また、ステートメントを準備する必要があることに注意してください。これはここで何度も答えられています、もしあなたがそれに慣れていないなら、それについて読んでください、それは一行の価値があります。オブジェクト指向にステップインしている間、コードを繰り返さないためのより良い方法があります(DRY:自分自身を繰り返さないでください)(すでに手続き型でこれを行う必要があります)。

これをすべて1つのクラスにまとめることが問題になるように、代わりにそれを独自のクラスに入れます。

class DatabaseModelBase
{
    protected $connection;

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

    protected function prepare($query) {
        $connection = $this->connection;
        $statement = $connection->prepare($query);
        if (!$statement) {
            throw new DatabaseException(
                sprintf('(%s) %s', $connection->error, $connection->errno)
            );
        }
        return $statement;
    }
}

class Option extends DatabaseModelBase
{
    public function find($id) {
        $statement = $this->prepare('SELECT `option` FROM config WHERE id=?');
        $statement->bind_param('i', $id);
        $statement->execute();
        $statement->bind_result($option);
        $statement->fetch();
        $statement->close();

        return $option;
    }
}

ほとんどの場合、SQLクエリで間違いが発生するため、これには拡張エラー処理が含まれています。ご覧のとおり、特定のデータをフェッチする個々の関数は、独自のクラスに配置されています。このようなクラスを使用して、特定のデータ型のフェッチと更新をグループ化できます。

完全な使用法:

$dbConnection = new Connection(DB_HOST, DB_USER, DB_PASS, DB_NAME);

$option = new Option($dbConnection);

$optionValue = $option->find(1);

echo $optionValue; # value for option with ID1

オブジェクトの名前はOptionおそらくうまくいきません。私は例を軽量に保つようにしましたが、ある程度の分離も提供しました。他のシナリオでは、db接続にアクセスする別の種類の方法を選択することをお勧めします。これは、db接続がOptionコンストラクターを介して注入されOption、データベース接続が作成される方法の詳細を処理しなくなるためです。

たとえば、データベース接続オブジェクトをよりスマートにして、prepareまたはqueryを実際に使用するときに初めてデータベースに接続することができます。そのため、データベース接続を必要としないWebサイトへの要求は、不必要にデータベースに接続することはありません。

他の質問でさらに多くの例を見つけ、依存性注入について学びたいと思うかもしれません。また、常に物事を互いに離しておく必要があるため、互いに軽く接続されているだけのオブジェクトがいくつかあります。

于 2012-09-20T00:53:30.507 に答える
3

クラス内でもデータベースへの接続を移動することをお勧めします。

class myDB extends mysqli
{
  private $link;

  public function Connect()
  {
    $this->link = mysqli_connect(DB,HOST,DB_USER,DB,PASS,DB_NAME) or die(mysql_error());
  }

  public function getConfig($id) // thanks cbuckley
  {
     $res = mysqli_query($this->link,"SELECT * from config where id='$id'");
     $row = mysqli_fetch_array($res);
     return $row['option'];
   }    
}

そして、次のように使用します。

include('inc/dbc.php'); 
$db = new MyDB();
$db->Connect(); 
echo $db->getConfig(1);
于 2012-09-19T11:45:21.750 に答える
2

mysqliクラスを拡張する代わりに、新しいクラスでラップすることをお勧めします。構成が必要なクラスの場合は、依存性注入を使用した構成を含めるだけです。これにより、構成が必要なコードが、構成がその値を取得する方法について知る必要がないという利点がもたらされます。後でiniFileから構成を解析することにした場合は、Configuration-Classを変更するか、それ以上の方法で、ConfigurationInterfaceを実装する新しいクラスを作成し、新しいConfigurationClassを挿入するだけです。

class Configuration implements ConfigurationInterface{
        private $mysqli;

        public function construct(mysqli $mysqli) {
            $this->mysqli = $mysqli;
        }

        public function get($key) 
        {
            // You should escape this query to prevent SQL-injection
            $res = $this->mysqli->query("SELECT * from config where id='$key'");
            $row = $res>fetch_array();
            return $row['option'];
        }
    }

interface ConfigurationInterface {
    public get($key);
}

次のように使用します。

$mysqli = new mysqli('localhost', 'root', 'pw', 'my_db');
$config = new Configuration($mysqli);

var_dump($config->get(0));
于 2012-09-19T12:23:29.130 に答える