с текстовым файлом, я так и не разобрался --- Добавлено --- то есть метод PHP: public function getUserName() { $sql = $this->db->query("SELECT `login` FROM `users` WHERE id='" .$this->id . "'"); $res = $sql->fetchColumn(); return $res; } надо прописать в классе DB? Что значит представлять пользователя? Нагуглил 3 способа, какой из них лучше? 1) PHP: public function viewUser($id) { return User::model()->findByPk($id); } 2) PHP: public function viewUser($id) { return DB::select('*')->from('users')->where("id", '=', $id); } 3) PHP: public function viewUser($id) { $sql = 'SELECT * FROM users WHERE id=?'; return DB::prepare($sql)->execute([$id])->fetch(); }
надо будет и мне почитать.. а то я почему думал что если модель User то она должна как раз работать с базой... вроде как в yii2 с AR
Ну AR - это немного другое, да. Этот паттерн работает с базой сам, + представляет доменный объект бизнес-логики. Поэтому он нарушает принцип единственной обязанности и считается антипаттерном, хотя, при экспресс-разработки программ бывает полезен. Вы код Laravel что-ли показываете? Ну все три случая - атас, потому что в контроллере лезем в базу, при этом для Laravel первый лучше. Но самое лучшее было бы так (в Laravel): PHP: public function viewUser($id, UserRepository $userRepo) { return $userRepo->getUser($id); } Причём, Laravel можно настроить так, чтоб UserRepository он сам создавал и передавал в этот метод. Не всегда так делаю, зависит от сложности проекта.
Димон ты до этого говорил что понимаешь что пишешь, зачем просто гуглить и спрашивать что лучше? У тебя еще в первом примере было про класс DB. Нужно создать класс DB (и объект если не статика), затем запрос с параметром в который попадает аргумент от юзера. Обрати внимание в твоем примере "getUserName()" скобки пустые в отличии от 3 примеров от гугла.
@keren, не пиши хрень. Ну ты не очень понимаешь суть ООП. Классы и объекты должны быть отражением реальных объектов предметной области Каждый экземпляр класса User - это внутреннее представление пользователя твоей системы. Т.е. в нём содержатся данные этого пользователя, возможно, какие это методы работы с этими данными. Данные, полученные из базы, должны стать экземплярами этого класса. Вот по поводу того, как это произойдёт, есть несколько подходов. Есть паттерн ActiveRecord (https://ru.wikipedia.org/wiki/ActiveRecord), который предполагает, что этот класс сам знает, как сохранить себя в таблицах. Другой подход - DataMapper, http://designpatternsphp.readthedocs.io/ru/latest/Structural/DataMapper/README.html, который более соответствует правилам ООП, поскольку логика работы с базой сосредоточена в другом классе. У Зандстры, в принципе, описана развитая структура DataMapper, и решены основные задачи.
Примеры, которые @Dimon2x привёл "из гугла", явно код на фреймворке. Правда, Laravel - это я ошибся, не внимательно посмотрел. Там Yii1 вроде как, но не суть. Код, который от самого @Dimon2x, там и не нужен параметр методу, поскольку он обращается прямо к своему полю id
@mkramer Хочу сделать что-то типа такого PHP: return DB::select('*')->from('users')->where("id",'=',$id); Пытаюсь составить запрос и посмотреть, что получилось, но почему вылазит ошибка Catchable fatal error: Method User::__toString() must return a string value PHP: <?php class Db { private static $db; private static $host = 'localhost'; private static $dbname = 'test'; private static $charset = 'utf8'; private static $username = 'root'; private static $password = ''; private $select; private $from; private $id; static function connect() { if(empty(self::$db)) { self::$db = new PDO("mysql:host=".self::$host.";dbname=".self::$dbname.";charset=".self::$charset, self::$username, self::$password); } return self::$db; } public function select($mark) { $this->select = 'SELECT ' . $mark; return $this; } public function from($table) { $this->from = ' FROM ' . $table; return $this; } public function where($id) { $this->where = ' WHERE id = ' . $id; return $this; } } class User extends Db { public function __toString() { return $this->viewUser(); } public function viewUser() { return Db::select('*')->from('users')->where('1'); } } $user = new User; echo $user->viewUser(); --- Добавлено --- убрал __toString и сделал так PHP: print_r((array)$user->viewUser()); и получился какой-то бред Array ( [Dbselect] => SELECT * [Dbfrom] => FROM users [Dbid] => [where] => WHERE id = 1 )
Вы же после метода where возвращаете объект, котоый пытаетесь вывести на страницу. Поэтому и задействуется магический метод.
Ну у тебя метод __toString() возвращает объект класса User, а должен возвращать строку. И это, почему у тебя пользователь наследуется от соединения с базой данных? У тебя получается, что любой пользователь является соединением с базой данных. А если учесть, что у тебя же что-то ещё будет, у тебя будет что и посты пользователя - это соединения с базой данных, и всё на свете. --- Добавлено --- Ну что написал, то и получил Если очень хочется свой query builder написать, то они не так работают. Они копят все where, join-ы и прочее у себя в массивах, а потом компилируют это в запрос на самой последней стадии. У меня желания писать свой как-то не возникало - их полно готовых. Ну так тогда сначала надо было разобрать доку по фреймворку, в котором так сделано (кажется, это Yii1, хотя не знаю, я первый yii не пользовал).
Сначала определиться, что за задачу ты хочешь решить этим кодом. У тебя пока какие-то эксперименты ради экспериментов, без понимания происходящего
Ну так я тебе уже много раз указал, как это сделать правильно. И где прочитать. Но опять - читать книжки умные - нет, думать, прежде чем писать код - нет, даёшь ООП за 2 секунды на форуме...
@Dimon2x, я бы не советовал такое делать вообще. На то есть как минимум две причины: 1. Сужается спектр возможных запросов. Так как предугадать все необходимые варианты невозможно. 2. Практическая ценность равна нулю - все равно приходится писать select, from, where
@Maputo, ну Query Builder-ы удобны часто, но писать самому - удавиться легче. Те, которые во фрейморках, позволяют сделать запрос почти любой сложности
@mkramer @Maputo Здесь подключение к БД, происходит только 1 раз? PHP: <?php error_reporting(E_ALL); class DB { private static $db; private static $host = 'localhost'; private static $dbname = 'test'; private static $charset = 'utf8'; private static $username = 'root'; private static $password = ''; static public function connect() { if (self::$db === null) { self::$db = new PDO("mysql:host=".self::$host.";dbname=".self::$dbname.";charset=".self::$charset, self::$username, self::$password); } return static::$db; } } class User { private $id; private $db; public function __construct() { $this->db = DB::connect(); } public function getUserName($id) { $this->id = $id; $sql = $this->db->query("SELECT * FROM `users` WHERE id='" .$this->id . "'"); $res = $sql->fetch(PDO::FETCH_ASSOC); return $res; } public function getAllUsers() { $sql = $this->db->query("SELECT * FROM `users`"); $res = $sql->fetchAll(PDO::FETCH_ASSOC); return $res; } } $user = new User; echo '<pre>'; print_r($user->getUserName('1')); echo '</pre>'; echo '<pre>'; print_r($user->getAllUsers()); echo '</pre>';
Здесь, в моём классе, хоть какой-то есть плюс, в отличие, если тоже самое сделать в функциональном стиле? Например в функциональном стиле, каждый раз придётся подключаться к бд, а это уже минус
@Dimon2x, плюсы определенно есть. Даже больше. По такому принципу построенно много классов с подключением к БД.
Не сказал бы что фанарную билдерку сложно написать, там по сути работы на пару дней то. я вот например использую вот такой простенький класс у себя сейчас в проектах, накалякал его за пару часиков правда там Join ы не предусмотрены --- Добавлено --- PHP: <?php /** * Created by PhpStorm. * User: strim * Date: 12.10.2017 * Time: 16:17 */ namespace Application\Model\Book; use Application\System\Model\DB; class Book { private $table = ''; private $dbConnect = Null; // return \PDO private $where = ''; private $sort = ''; private $limit = ''; private $order = ''; private $test = 0; public function __construct($table_name, $test = 0) { $this->table = $table_name; $this->test = $test; $this->dbConnect = DB::connect(); } public function where($where) { $stringIns = []; foreach ($where As $key => $value) { $stringIns[] = sprintf('%s=%s', $key, $this->dbConnect->quote($value)); } $this->where = implode(' AND ', $stringIns); $this->where = trim($this->where, ' AND '); return $this; } public function whereIN ($key, $charlist) { $and = ''; if (!empty($this->where)) $and = ' AND '; $this->where .= $and.$key. ' IN('.$charlist.')'; return $this; } public function order($order = 'id DESC') { $this->where .= ' ORDER BY '.$order; return $this; } public function limit( $min = 0, $max = 9999) { $this->limit = ' LIMIT '.$min.','.$max; return $this; } public function getCountQuery ($where) { if (empty($this->table)) return false; if (empty($this->where)) $this->where($where); $sql = 'SELECT count(id) As count_row FROM '.$this->table.' WHERE '.$this->where; $dbh = $this->dbConnect->query($sql); if ($dbh === false) { echo $sql; exit; } return $dbh->fetch(\PDO::FETCH_ASSOC); } public function getBook () { if (empty($this->table) or empty($this->where)) return false; $sql = 'SELECT * FROM '.$this->table.' WHERE '.$this->where.$this->order.$this->limit; if ($this->test == 1) { echo $sql; return []; } else if ($this->test == 0) { $dbh = $this->dbConnect->query($sql); return $dbh->fetchAll(\PDO::FETCH_ASSOC); } } public function update($array) { if (empty($this->table) or empty($this->where)) return false; if (empty($array)) return false; $stringIns = []; foreach ($array As $key => $value) { $stringIns[] = sprintf('%s=%s', $key, $this->dbConnect->quote($value)); } $str = implode(' , ', $stringIns); $str= trim($str, ' , '); $sql = 'UPDATE '.$this->table.' SET '.$str.' WHERE '.$this->where.$this->order.$this->limit; $dbh = $this->dbConnect->query($sql); return $dbh; } public function getFetch() { if (empty($this->table) or empty($this->where)) return false; $sql = 'SELECT * FROM '.$this->table.' WHERE '.$this->where.$this->order; $dbh = $this->dbConnect->query($sql); return $dbh->fetch(\PDO::FETCH_ASSOC); } public function del() { if (empty($this->table) or empty($this->where)) return false; $sql = 'DELETE FROM '.$this->table.' WHERE '.$this->where.$this->order.$this->limit; $dbh = $this->dbConnect->query($sql); } }
@askanim, ну так у тебя не только join-ов нету. Чтоб универсальный билдер написать, надо реализовать джоины, операции типа больше, меньше, равно/неравно, OR и прочее и прочее. Ну и лично мне не нравится, что ты возвращаешь из класса не доменные объекты, а обычные ассоциативные массивы
Мы говорим про ORM или query builder ? --- Добавлено --- Насколько я помню только в active rexcord это позиция работает типа doctrine там и т.д Но такой подход несёт за собой не мало дебатов по поводу скорости работы приложения. Я честно говоря отказался от использования ORM и ушёл бы в сторону либо просто запросов либо вот таких как у меня query builder почему? Да потому что работает быстрее в разы! --- Добавлено --- Потому что весь ваш ORM Просто куча бесполезных данных. Да на нём быстро и удобно (Разрабатывать), не спорю, но он проигрывает обычному ДАО в скорости исполнения. Да нет у мну join но можно пикси притянуть там есть обычная query builderka --- Добавлено --- А ещё я могу их и дописать к себе при желании просто они мне не нужны я вообще наверное стал сторонник делаем приложение без join --- Добавлено --- Потому что опять же быстрее два запроса нежели один тяжёлый. --- Добавлено --- Хотя не всегда, зависит от случая конечно - с джоинами. Но тут по сути над тестить и будет видно, но это уже другая охота на ведьм. В нашем случае ORM на мой взгляд это бредовая конструкция, не спорю интересная но бредовая --- Добавлено --- С этим согласен, для универсального нужны, но я писал чисто на скорую руку то что нужно было. По мере необходимости дописываю методы. --- Добавлено --- Конечно по хорошему нужно вообще уделить этому пару дней, но максимум что у меня было это 2 часа
Не хочешь ActiveRecord - пользую DataMapper, у него нету проигрыша по скорости, если самостоятельно реализовать, но ОО-программа должна работать с объектами, ИМХО. У Зандстры кстати прикольная в конце система разработана для взаимодействия с БД Doctrine, кстати, DataMapper, но там они пытались быть суперуниверсальными, и используют аннотации, т.е. сканируют исходные файлы.