少し紹介してみましょう。私はPHPでOOPを学ぶ過程にあります。私はDesign Patternsも研究しましたが、さまざまなタイプの概念をまだ完全には把握していません。私は数ヶ月おきに私が正しいことをやっているわけではなく、自分のスタイルを変えなければならないことを認識しています。 これはとてもイライラです。それゆえ、私は物事を一回だけ行う正しい方法を見出したいと思います。私は完全には、次のトピックについてStackOverflowの上に読むことを試みている:私はまだいくつかのことについて明確ではないよしかしPHPでOOPプログラミングでクラスを設定する正しい方法は何ですか?
ORM
データマッパー
シングルトン
グローバルは
関連
すべて悪です。私はここに明確かつ簡潔な方法で私のコードを掲載しています。人々がの両方を指摘できることを願っています。は良い方法と悪い方法です。最後にすべての質問をリストアップします。
私は正直に話題のほぼすべての質問を検索しましたが、私はまだ明らかにできなかったいくつかのことを知りたいと思います。申し訳ありませんが、それはとても長いですが、私はそれを整理しようとしましたので、よく読んでください!
私は、データベースクラスの本質を投稿することから始めます。
database.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);
}
}
?>
これは私のDatabaseクラスファイルです。このクラスは私がこのクラスのように多くのインスタンスを作成することを可能にし、クラスのStaticプロパティとして格納されている既にインスタンス化された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 Bindingsを使用して呼び出されるクラスの名前にアクセスし、$stmt->fetchAll(PDO::FETCH_CLASS, $class_name)
を使用して、これらのオブジェクトをデータベースからのデータでインスタンス化し、自動的にオブジェクトに変換します。
各静的メソッドでは、DatabaseMySQLクラスのインスタンスをインスタンス化します。それぞれの静的メソッドでは、クラスの名前を取得してs
を追加することによって、動的にSQLクエリで使用される正しい静的な名前$table
を設定しました。だから私のクラスがUser
だったら、テーブル名はusers
になります。
私のコンストラクタでは、オブジェクトのプロパティとして変数を挿入するために使用できるオプションの配列を作成しました。このようにすべてが動的に行われるため、私は自分のプロジェクトの最終段階にいられます。私の継承クラス。
User.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::find_by_id(1);
echo $user->username; // prints users name
:
1)それが一つでも全く).dataのマッパーである場合は、(このデザインパターンを呼ぶものの名前は?依存性注射?ドメインモデル(それが何であれ)?データアクセス層?
2)今のところ、この実装はうまく構成されていると考えられますか?
3)良いことがあれば、私のコードには欠落していることを知っておくべき命名規則がありますか?
4)あなたが特に気に入った点を指摘してもよろしいので、どの部分を確実に保存するか分かりますか?
5)なぜそれが良いのではないかと思われる場合は、詳細な説明をしてください。
6)万一私の
create
、update
、私のfind_by_id
、唯一の静的と呼ばれているfind_all
と同じクラスになると、実際にオブジェクトを返す私のオブジェクトのすべてのメソッドをしているdelete
。彼らが2つの異なるクラスにいなければならない場合は、どうすればよいですか?7)なぜ誰もが
$load->('UserClass')
機能を使用し、マッパーのような派手な言葉を使用していますが、私は一度もそれらを必要としませんでしたか?
これは、ここに適合します:http://codereview.stackexchange.com/ –
@IliaRostovtsev私はそれを知っていませんでしたが、私はまだ専門家からの答えがほしいと思う、私は彼らが主にここにいると思う! –
No.話題だけを読んではいけません(私はSOを最初の参照として使用することをお勧めしません)。経験を積む、あなたの手を汚くするのを恐れないでください(この質問は良いスタートです)。黒と白がないことを知ってください。文脈はわかりませんが、グローバルは必ずしも悪いものではなく、悪用されると恐ろしいものです。 ORMとシングルトンの場合と同じことですが、すべての場合、それは良い習慣ですが、必ずしもベストではありません。 – skytreader