За последние 24 часа нас посетили 18096 программистов и 1700 роботов. Сейчас ищут 1533 программиста ...

Практика использование ООП

Тема в разделе "PHP для новичков", создана пользователем Dimon2x, 26 ноя 2017.

  1. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
  2. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
    с текстовым файлом, я так и не разобрался
    --- Добавлено ---
    то есть метод

    PHP:
    1. public function getUserName() {
    2.      $sql = $this->db->query("SELECT `login` FROM `users` WHERE id='" .$this->id . "'");
    3.     $res = $sql->fetchColumn();
    4.          return $res;
    5.     }
    надо прописать в классе DB?

    Что значит представлять пользователя?


    Нагуглил 3 способа, какой из них лучше?

    1)
    PHP:
    1. public function viewUser($id)
    2. {
    3.     return User::model()->findByPk($id);
    4. }
    2)
    PHP:
    1. public function viewUser($id)
    2. {
    3.     return DB::select('*')->from('users')->where("id", '=', $id);
    4. }
    3)

    PHP:
    1. public function viewUser($id)
    2. {
    3.     $sql = 'SELECT * FROM users WHERE id=?';
    4.     return DB::prepare($sql)->execute([$id])->fetch();
    5. }
     
  3. Алекс8

    Алекс8 Активный пользователь

    С нами с:
    18 май 2017
    Сообщения:
    1.730
    Симпатии:
    359
    надо будет и мне почитать..
    а то я почему думал что если модель User то она должна как раз работать с базой...
    вроде как в yii2 с AR
     
  4. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    Ну AR - это немного другое, да. Этот паттерн работает с базой сам, + представляет доменный объект бизнес-логики. Поэтому он нарушает принцип единственной обязанности и считается антипаттерном, хотя, при экспресс-разработки программ бывает полезен.
    Вы код Laravel что-ли показываете? Ну все три случая - атас, потому что в контроллере лезем в базу, при этом для Laravel первый лучше. Но самое лучшее было бы так (в Laravel):
    PHP:
    1. public function viewUser($id, UserRepository $userRepo)
    2. {
    3.     return $userRepo->getUser($id);
    4. }
    Причём, Laravel можно настроить так, чтоб UserRepository он сам создавал и передавал в этот метод. Не всегда так делаю, зависит от сложности проекта.
     
  5. keren

    keren Новичок

    С нами с:
    15 ноя 2017
    Сообщения:
    513
    Симпатии:
    42
    Димон ты до этого говорил что понимаешь что пишешь, зачем просто гуглить и спрашивать что лучше? У тебя еще в первом примере было про класс DB.
    Нужно создать класс DB (и объект если не статика), затем запрос с параметром в который попадает аргумент от юзера.
    Обрати внимание в твоем примере "getUserName()" скобки пустые в отличии от 3 примеров от гугла.
     
    #155 keren, 3 дек 2017
    Последнее редактирование: 3 дек 2017
  6. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    @keren, не пиши хрень.
    Ну ты не очень понимаешь суть ООП. Классы и объекты должны быть отражением реальных объектов предметной области

    Каждый экземпляр класса User - это внутреннее представление пользователя твоей системы. Т.е. в нём содержатся данные этого пользователя, возможно, какие это методы работы с этими данными. Данные, полученные из базы, должны стать экземплярами этого класса. Вот по поводу того, как это произойдёт, есть несколько подходов. Есть паттерн ActiveRecord (https://ru.wikipedia.org/wiki/ActiveRecord), который предполагает, что этот класс сам знает, как сохранить себя в таблицах. Другой подход - DataMapper, http://designpatternsphp.readthedocs.io/ru/latest/Structural/DataMapper/README.html, который более соответствует правилам ООП, поскольку логика работы с базой сосредоточена в другом классе. У Зандстры, в принципе, описана развитая структура DataMapper, и решены основные задачи.
     
  7. keren

    keren Новичок

    С нами с:
    15 ноя 2017
    Сообщения:
    513
    Симпатии:
    42
    Может обоснуешь, я что понимаю то и пишу.
     
  8. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    Примеры, которые @Dimon2x привёл "из гугла", явно код на фреймворке. Правда, Laravel - это я ошибся, не внимательно посмотрел. Там Yii1 вроде как, но не суть. Код, который от самого @Dimon2x, там и не нужен параметр методу, поскольку он обращается прямо к своему полю id
     
    keren нравится это.
  9. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
    @mkramer

    Хочу сделать что-то типа такого
    PHP:
    1. return DB::select('*')->from('users')->where("id",'=',$id);
    Пытаюсь составить запрос и посмотреть, что получилось, но почему вылазит ошибка Catchable fatal error: Method User::__toString() must return a string value

    PHP:
    1. <?php
    2.     class Db {
    3.         private static $db;
    4.         private static $host = 'localhost';
    5.         private static $dbname = 'test';
    6.         private static $charset = 'utf8';
    7.         private static $username = 'root';
    8.         private static $password = '';
    9.        
    10.         private $select;
    11.         private $from;
    12.         private $id;
    13.        
    14.         static function connect() {
    15.             if(empty(self::$db)) {
    16.                  self::$db = new PDO("mysql:host=".self::$host.";dbname=".self::$dbname.";charset=".self::$charset,
    17.                                         self::$username, self::$password);
    18.             }
    19.            
    20.             return self::$db;
    21.         }
    22.    
    23.    
    24.         public function select($mark) {
    25.             $this->select = 'SELECT ' . $mark;
    26.             return $this;
    27.         }
    28.        
    29.         public function from($table) {
    30.             $this->from = ' FROM ' . $table;
    31.             return $this;
    32.         }
    33.        
    34.         public function where($id) {
    35.             $this->where = ' WHERE id = ' . $id;
    36.             return $this;
    37.         }
    38.        
    39.     }
    40.    
    41.     class User extends Db {
    42.         public function __toString() {
    43.             return $this->viewUser();
    44.         }
    45.        
    46.         public function viewUser() {
    47.             return Db::select('*')->from('users')->where('1');
    48.         }
    49.     }
    50.    
    51.     $user = new User;
    52.     echo $user->viewUser();
    --- Добавлено ---
    убрал __toString и сделал так

    PHP:
    1. print_r((array)$user->viewUser());
    и получился какой-то бред

    Array ( [Dbselect] => SELECT * [Dbfrom] => FROM users [Dbid] => [where] => WHERE id = 1 )
     
  10. Maputo

    Maputo Активный пользователь

    С нами с:
    30 июл 2015
    Сообщения:
    1.136
    Симпатии:
    173
    Вы же после метода where возвращаете объект, котоый пытаетесь вывести на страницу. Поэтому и задействуется магический метод.
     
  11. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    Ну у тебя метод __toString() возвращает объект класса User, а должен возвращать строку. И это, почему у тебя пользователь наследуется от соединения с базой данных? У тебя получается, что любой пользователь является соединением с базой данных. А если учесть, что у тебя же что-то ещё будет, у тебя будет что и посты пользователя - это соединения с базой данных, и всё на свете.
    --- Добавлено ---
    Ну что написал, то и получил :) Если очень хочется свой query builder написать, то они не так работают. Они копят все where, join-ы и прочее у себя в массивах, а потом компилируют это в запрос на самой последней стадии. У меня желания писать свой как-то не возникало - их полно готовых.
    Ну так тогда сначала надо было разобрать доку по фреймворку, в котором так сделано (кажется, это Yii1, хотя не знаю, я первый yii не пользовал).
     
  12. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
    @Maputo @mkramer как мне сделать, что бы заработало?
     
  13. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    Сначала определиться, что за задачу ты хочешь решить этим кодом. У тебя пока какие-то эксперименты ради экспериментов, без понимания происходящего
     
  14. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
    @mkramer я хочу вывести список юзеров
     
  15. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    Ну так я тебе уже много раз указал, как это сделать правильно. И где прочитать. Но опять - читать книжки умные - нет, думать, прежде чем писать код - нет, даёшь ООП за 2 секунды на форуме...
     
    askanim нравится это.
  16. Maputo

    Maputo Активный пользователь

    С нами с:
    30 июл 2015
    Сообщения:
    1.136
    Симпатии:
    173
    @Dimon2x, я бы не советовал такое делать вообще. На то есть как минимум две причины:
    1. Сужается спектр возможных запросов. Так как предугадать все необходимые варианты невозможно.
    2. Практическая ценность равна нулю - все равно приходится писать select, from, where
     
  17. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    @Maputo, ну Query Builder-ы удобны часто, но писать самому - удавиться легче. Те, которые во фрейморках, позволяют сделать запрос почти любой сложности
     
    #167 mkramer, 3 дек 2017
    Последнее редактирование: 3 дек 2017
    Maputo нравится это.
  18. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
    @mkramer @Maputo Здесь подключение к БД, происходит только 1 раз?

    PHP:
    1. <?php
    2.     error_reporting(E_ALL);
    3.    
    4.     class DB
    5.     {
    6.         private static $db;
    7.         private static $host = 'localhost';
    8.         private static $dbname = 'test';
    9.         private static $charset = 'utf8';
    10.         private static $username = 'root';
    11.         private static $password = '';
    12.        
    13.         static public function connect()
    14.         {
    15.             if (self::$db === null) {
    16.                 self::$db = new PDO("mysql:host=".self::$host.";dbname=".self::$dbname.";charset=".self::$charset,
    17.                                         self::$username, self::$password);
    18.             }
    19.             return static::$db;
    20.         }
    21.    
    22.     }
    23.    
    24.     class User {
    25.         private $id;
    26.         private $db;
    27.        
    28.         public function __construct()
    29.         {
    30.             $this->db = DB::connect();
    31.         }
    32.        
    33.         public function getUserName($id) {
    34.             $this->id = $id;
    35.             $sql = $this->db->query("SELECT * FROM `users` WHERE id='" .$this->id . "'");
    36.             $res = $sql->fetch(PDO::FETCH_ASSOC);
    37.             return $res;
    38.         }
    39.        
    40.         public function getAllUsers() {
    41.             $sql = $this->db->query("SELECT * FROM `users`");
    42.             $res = $sql->fetchAll(PDO::FETCH_ASSOC);
    43.             return $res;
    44.         }
    45.  
    46.     }
    47.    
    48.     $user = new User;
    49.    
    50.     echo '<pre>';
    51.         print_r($user->getUserName('1'));
    52.     echo '</pre>';
    53.    
    54.     echo '<pre>';
    55.         print_r($user->getAllUsers());
    56.     echo '</pre>';
     
  19. Maputo

    Maputo Активный пользователь

    С нами с:
    30 июл 2015
    Сообщения:
    1.136
    Симпатии:
    173
    @Dimon2x, если никто потом не переопределит соединение, то да.
     
  20. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
    Здесь, в моём классе, хоть какой-то есть плюс, в отличие, если тоже самое сделать в функциональном стиле? Например в функциональном стиле, каждый раз придётся подключаться к бд, а это уже минус
     
  21. Maputo

    Maputo Активный пользователь

    С нами с:
    30 июл 2015
    Сообщения:
    1.136
    Симпатии:
    173
    @Dimon2x, плюсы определенно есть. Даже больше. По такому принципу построенно много классов с подключением к БД.
     
  22. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    Не сказал бы что фанарную билдерку сложно написать, там по сути работы на пару дней то. я вот например использую вот такой простенький класс у себя сейчас в проектах, накалякал его за пару часиков правда там Join ы не предусмотрены
    --- Добавлено ---
    PHP:
    1. <?php
    2. /**
    3. * Created by PhpStorm.
    4. * User: strim
    5. * Date: 12.10.2017
    6. * Time: 16:17
    7. */
    8.  
    9. namespace Application\Model\Book;
    10.  
    11.  
    12. use Application\System\Model\DB;
    13.  
    14. class Book
    15. {
    16.     private $table = '';
    17.     private $dbConnect = Null; // return \PDO
    18.     private $where = '';
    19.     private $sort = '';
    20.     private $limit = '';
    21.     private $order = '';
    22.     private $test = 0;
    23.     public function __construct($table_name, $test = 0)
    24.     {
    25.         $this->table = $table_name;
    26.         $this->test = $test;
    27.         $this->dbConnect = DB::connect();
    28.  
    29.     }
    30.     public function where($where) {
    31.         $stringIns = [];
    32.         foreach ($where As $key => $value) {
    33.             $stringIns[] = sprintf('%s=%s', $key, $this->dbConnect->quote($value));
    34.         }
    35.         $this->where = implode(' AND ', $stringIns);
    36.         $this->where = trim($this->where, ' AND ');
    37.         return $this;
    38.     }
    39.     public function whereIN ($key, $charlist) {
    40.         $and = '';
    41.         if (!empty($this->where)) $and = ' AND ';
    42.         $this->where .= $and.$key. ' IN('.$charlist.')';
    43.  
    44.         return $this;
    45.  
    46.     }
    47.     public function order($order = 'id DESC') {
    48.         $this->where .= ' ORDER BY '.$order;
    49.         return $this;
    50.     }
    51.     public function limit( $min = 0, $max = 9999) {
    52.         $this->limit = ' LIMIT '.$min.','.$max;
    53.         return $this;
    54.     }
    55.     public function getCountQuery ($where) {
    56.         if (empty($this->table)) return false;
    57.         if (empty($this->where)) $this->where($where);
    58.         $sql = 'SELECT count(id) As count_row FROM '.$this->table.' WHERE '.$this->where;
    59.         $dbh = $this->dbConnect->query($sql);
    60.         if ($dbh === false) {
    61.             echo $sql;
    62.             exit;
    63.         }
    64.         return $dbh->fetch(\PDO::FETCH_ASSOC);
    65.     }
    66.     public function getBook () {
    67.         if (empty($this->table) or empty($this->where)) return false;
    68.         $sql = 'SELECT * FROM '.$this->table.' WHERE '.$this->where.$this->order.$this->limit;
    69.         if ($this->test == 1) {
    70.             echo $sql;
    71.             return [];
    72.         }
    73.         else if ($this->test == 0) {
    74.             $dbh = $this->dbConnect->query($sql);
    75.             return $dbh->fetchAll(\PDO::FETCH_ASSOC);
    76.         }
    77.     }
    78.     public function update($array) {
    79.         if (empty($this->table) or empty($this->where)) return false;
    80.         if (empty($array)) return false;
    81.         $stringIns = [];
    82.         foreach ($array As $key => $value) {
    83.             $stringIns[] = sprintf('%s=%s', $key, $this->dbConnect->quote($value));
    84.         }
    85.         $str = implode(' , ', $stringIns);
    86.         $str= trim($str, ' , ');
    87.         $sql = 'UPDATE '.$this->table.' SET '.$str.' WHERE '.$this->where.$this->order.$this->limit;
    88.         $dbh = $this->dbConnect->query($sql);
    89.         return $dbh;
    90.     }
    91.     public function getFetch() {
    92.         if (empty($this->table) or empty($this->where)) return false;
    93.         $sql = 'SELECT * FROM '.$this->table.' WHERE '.$this->where.$this->order;
    94.         $dbh = $this->dbConnect->query($sql);
    95.         return $dbh->fetch(\PDO::FETCH_ASSOC);
    96.     }
    97.     public function del() {
    98.         if (empty($this->table) or empty($this->where)) return false;
    99.         $sql = 'DELETE FROM '.$this->table.' WHERE '.$this->where.$this->order.$this->limit;
    100.         $dbh = $this->dbConnect->query($sql);
    101.     }
    102. }
     
    Dimon2x нравится это.
  23. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    @askanim, ну так у тебя не только join-ов нету. Чтоб универсальный билдер написать, надо реализовать джоины, операции типа больше, меньше, равно/неравно, OR и прочее и прочее. Ну и лично мне не нравится, что ты возвращаешь из класса не доменные объекты, а обычные ассоциативные массивы
     
    Maputo нравится это.
  24. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    Мы говорим про ORM или query builder ?
    --- Добавлено ---
    Насколько я помню только в active rexcord это позиция работает типа doctrine там и т.д Но такой подход несёт за собой не мало дебатов по поводу скорости работы приложения. Я честно говоря отказался от использования ORM и ушёл бы в сторону либо просто запросов либо вот таких как у меня query builder почему? Да потому что работает быстрее в разы!
    --- Добавлено ---
    Потому что весь ваш ORM Просто куча бесполезных данных. Да на нём быстро и удобно (Разрабатывать), не спорю, но он проигрывает обычному ДАО в скорости исполнения. Да нет у мну join но можно пикси притянуть там есть обычная query builderka
    --- Добавлено ---
    А ещё я могу их и дописать к себе при желании просто они мне не нужны я вообще наверное стал сторонник делаем приложение без join :D
    --- Добавлено ---
    Потому что опять же быстрее два запроса нежели один тяжёлый.
    --- Добавлено ---
    Хотя не всегда, зависит от случая конечно - с джоинами. Но тут по сути над тестить и будет видно, но это уже другая охота на ведьм. В нашем случае ORM на мой взгляд это бредовая конструкция, не спорю интересная но бредовая :)
    --- Добавлено ---
    С этим согласен, для универсального нужны, но я писал чисто на скорую руку то что нужно было. По мере необходимости дописываю методы.
    --- Добавлено ---
    Конечно по хорошему нужно вообще уделить этому пару дней, но максимум что у меня было это 2 часа :)
     
  25. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    Не хочешь ActiveRecord - пользую DataMapper, у него нету проигрыша по скорости, если самостоятельно реализовать, но ОО-программа должна работать с объектами, ИМХО. У Зандстры кстати прикольная в конце система разработана для взаимодействия с БД

    Doctrine, кстати, DataMapper, но там они пытались быть суперуниверсальными, и используют аннотации, т.е. сканируют исходные файлы.
     
    askanim нравится это.