少し紹介を始めましょう。私はPHPでOOPを学んでいます。デザイン パターンについても調べましたが、さまざまな種類の概念をまだ完全には把握していません。私は数か月ごとに、自分のやり方が正しくないことに気づき、自分のスタイルを変えなければならない段階にいます. これはとてもイライラします。したがって、物事を行う正しい方法を一度だけ見つけたいと思います。次のトピックについて、Stackoverflow を完全に読み込もうとしました。
ORM
Data Mapper
シングルトン
グローバルは悪です
関連するすべて
ただし、いくつかのことについてはまだ明確ではありません。私は自分のコードを明確かつ簡潔な方法でここに投稿しています。人々が良い方法と悪い方法の両方を指摘できることを願っています。最後にすべての質問をリストします。
重複して閉じないでください。このトピックに関するほぼすべての質問を正直に検索しましたが、まだ明確にできていないいくつかのことを知りたい. 長くなってすみませんが、よく読めるように整理してみました!
データベース クラスの要点を投稿することから始めます。
データベース.php
<?php
class DatabaseMySQL{
private static $dbh;
public function __construct(){
$this->open_connection();
}
public function open_connection(){
if(!self::$dbh){
return (self::$dbh = new PDO(DB_TYPE.':host='.DB_HOST.';dbname='.DB_NAME, DB_USER,DB_PASSWORD)) ? true : false;
}
return true;
}
public function query($sql, $params=array()){
$this->last_query = $sql;
$stmt = self::$dbh->prepare($sql);
$result = $stmt->execute($params);
return $result ? $stmt : $stmt->errorInfo();
}
public function fetch_all($results, $class_name=''){
return $results->fetchAll(PDO::FETCH_CLASS, $class_name);
}
}
?>
これは私のデータベース クラス ファイルです。このクラスを使用すると、このクラスのインスタンスを好きなだけ作成でき、クラスの静的プロパティとして格納されているインスタンス化済みの PDO オブジェクトを再利用できます。また、PDO を使用して結果セットからデータをフェッチし、指定されたクラスのオブジェクトとしてデータを取得します。
次のファイルは、他のすべてのクラスが継承するクラスです。私はこれを MainModel と呼んでいます。これが慣例に従っているかどうかはわかりません。
MainModel.php
<?php
abstract class MainModel{
protected static $table;
public function __construct($array=array()){
$this->assign_known_properties($array);
}
public function assign_known_properties($array){
foreach($array as $key=>$value){
$this->$key = $value;
}
}
public static function find_by_id($id){
$db = new DatabaseMySQL();
self::intialise_table_name();
$id = (int) $id;
$sql = "SELECT * FROM ".static::$table." ";
$sql .= "WHERE id = {$id} ";
$result = self::find_by_sql($sql);
return array_shift($result);
}
public static function find_all(){
$db = new DatabaseMySQL();
self::intialise_table_name();
$sql = "SELECT * FROM ".self::$table." ";
return self::find_by_sql($sql);
}
public static function fetch_as_objects($results){
$db = new DatabaseMySQL();
$called_class = get_called_class();
$results = $db->fetch_all($results, $called_class);
return $results;
}
public static function find_by_sql($sql){
$db = new DatabaseMySQL();
$results = $db->query($sql);
return $results ? self::fetch_as_objects($results) : false;
}
public static function intialise_table_name(){
$called_class = get_called_class();
static::$table = strtolower($called_class).'s';
}
public function get_table_fields(){
self::intialise_table_name();
$sql = "SHOW FIELDS FROM ".static::$table." ";
return self::find_by_sql($sql);
}
public function set_table_details(){
$fields = $this->get_table_fields();
$total = count($fields);
$array = array();
foreach($fields as $object){
$array [] = $object->Field;
}
$this->table_details = array('objects'=>$fields,'array'=>$array,'total'=>$total);
$this->set_placeholders_for_new_record();
$this->set_properties_as_array();
$this->set_properties_as_array(true);
}
public function set_properties_as_array($assoc=false){
$array = array();
if (!$assoc){
foreach($this->table_details['array'] as $field){
if(isset($this->$field)){
$array [] = $this->$field;
}else{
$array [] = NULL;
}
}
$this->table_details['values'] = $array;
}else{
foreach($this->table_details['array'] as $field){
if(isset($this->$field)){
$array[$field] = $this->$field;
}else{
$array [$field] = NULL;
}
}
$this->table_details['assoc_values'] = $array;
}
}
public function set_placeholders_for_new_record(){
$string = '';
for($i=0; $i<$this->table_details['total']; $i++){
$string .= '? ';
if(($i+1) != $this->table_details['total'] ){
$string .= ", ";
}
}
$this->table_details['placeholders'] = $string;
}
public function create(){
$db = new DatabaseMySQL();
$this->set_table_details();
$sql = "INSERT INTO ".static::$table." ";
$sql .= " VALUES({$this->table_details['placeholders']}) ";
$result = $db->query($sql, $this->table_details['values']);
// If array is returned then there was an error.
return is_array($result) ? $result : $db->insert_id();
}
public function update(){
$db = new DatabaseMySQL();
$this->set_table_details();
$sql = "UPDATE ".static::$table." ";
$sql .= " SET ";
$count = 1;
foreach($this->table_details['array'] as $field){
$sql .= "{$field} = :{$field} ";
if($count < $this->table_details['total']){
$sql .= ", ";
}
$count++;
}
$sql .= " WHERE id = {$this->id} ";
$sql .= " LIMIT 1 ";
$result = $db->query($sql, $this->table_details['assoc_values']);
return $result;
}
public function save(){
return isset($this->id) ? $this->update() : $this->create();
}
}
?>
このファイルを要約します。find_by_id($int)
呼び出されたクラスのオブジェクトを動的に生成するような静的メソッドを使用します。Late Static Binding を使用して、呼び出されたクラスの名前にアクセスし、 を使用し$stmt->fetchAll(PDO::FETCH_CLASS, $class_name)
て、データベースからのデータを自動的にオブジェクトに変換してこれらのオブジェクトをインスタンス化します。
各静的メソッドで、DatabaseMySQL クラスのインスタンスをインスタンス化します。$table
各静的メソッドでは、クラスの名前を取得してそれに追加することにより、SQL クエリで動的に使用される正しい静的名を設定しますs
。したがって、私のクラスが だった場合User
、テーブル名は になりますusers
。
私のコンストラクターでは、作成時にオブジェクトのプロパティとしていくつかの変数を挿入するために使用できるオプションの配列を配置しました。このようにして、すべてが動的に行われ、プロジェクトの最終段階に進みます。私の継承クラス。
ユーザー.php
class User extends MainModel{
}
Question.php
class Question extends MainModel{
}
私が今やっていることはシンプルです。私は言うことができます:
$user = new User(array('username'=>'John Doe'));
echo $user->username; // prints *John Doe*
$user->save(); // saves (or updates) the user into the database.
User への静的呼び出しでユーザーを取得できます。
$user = User::find_by_id(1);
echo $user->username; // prints users name
だから今私の質問のために:
1) このデザイン パターンを何と呼びますか? 依存性注入?ドメインモデル(それが何であれ)?データアクセスレイヤー?
2) 現状では、この実装は適切に構造化されていると考えられますか?
3) 良い場合、コードに欠けていることに注意する必要がある命名規則はありますか?
4) 良いと思われる場合は、特に気に入った点を指摘していただけますか?
5) 良いと思わない場合は、その理由を詳しく説明していただけますか?
6) my オブジェクトのすべてのメソッドである my
create
,はupdate
、静的にのみ呼び出され、実際にオブジェクトを返すmyとdelete
同じクラスにある必要があります。彼らが2つの異なるクラスにいる必要がある場合、どうすればいいですか?find_by_id
find_all
7) なぜ他の人は
$load->('UserClass')
関数やマッパーのような派手な言葉を使っているのに、私は一度もそれらを必要としたことがないのですか?