Профиль пользователя заблокирован сроком с 10 апреля 2022 г. и навсегда по причине: систематические нарушения правил сервиса
Ответы пользователя по тегу ООП
  • Как правильно передавать параметры в запрос PDO ООП?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    В рамках данного метода - никак.

    Чтобы подставлять имя таблицы в запрос, надо будет по настоящему учить ООП, и писать настоящие классы, а не то что у тебя сейчас - обычная функция, которой класс по сути не нужен.

    Если никто не соберется прочесть вопрос и написать нормальный ответ, я попробую найти время в выходные и доделать статью, где объясняется, как это делать правильно
    Ответ написан
    Комментировать
  • Как делать сложные запросы используя репозитории и объединение разных таблиц?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    решением этой несложной задачки.

    Уважаю такой оптимизм.

    Проблема эта не нова. Называется она object-relational impedance mismatch и очень многие считают её в принципе нерешаемой, сравнивая её с проигранной США войной во Вьетнаме.
    Так что можно надеяться на что угодно, только не на простое решение. Но сначала надо проблему осознать. Что отображение объектов на реляционную базу, которое называется object-relational mapping, сокращённо ORM, никогда не бывает простым.

    Отдельно этой теме добавляет остроты терминология. Спроси 10 разных разработчиков что они имеют в виду под репозиторием и под маппингом, и получишь 20 разных мнений. Так что использовать красивые слова следует с очень большой осторожностью.

    К примеру, "нерешаемость" проблемы с impedance mismatch относится к попыткам сделать универсальный ORM, который на вход получает имя любого класса, а на выходе коллекцию объектов. Про такой вариант можно действительно забыть (привет, элоквент-элоквент - и в продакшен!). Но вот полуавтоматическое решение вполне можно накостылить. Главное всегда помнить о проблеме, и как только автоматический маппинг перестаёт работать - тут же от него оказываться в пользу ручного колупания с запросами. Главное этого не бояться и не загонять себя в клетку словами "репозиторий", "один объект-одна таблица" и пр. У тебя есть задача - инстанцировать объект или коллекци объектов из БД. Окей, ты пишешь методы, которые это делают оптимальным способом, не важно - одна там таблица используется, 10 или еще плюс 2 кэша и носкл датабаза в придачу.
    Надо тебе сохранить объект или коллекци объектов в БД? Окей, пишешь метод, коорый делает это оптимальным способом. Да, это куча черной работы. Но зато у тебя будет чистая доменная логика (которая вообще никакого отношения к базе данных или "репозиториям" не имеет).

    Отдельно прекламирую Cycle ORM. Сам я ненастоящий сварщик, но взрослые дядьки говорят что она лучше всего подходит для нормально реализованного маппинга объектов на БД. Лучше чем Доктрина или прости-господи Элоквент. С нетерпением жду доклада автора на ПХПРаша.
    Ответ написан
    1 комментарий
  • Как обойтись без параметра для parent?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Всем изучающим ООП надо метровыми буквами написать во всю стену

    НАСЛЕДУЮТСЯ КЛАССЫ, А НЕ ОБЪЕКТЫ
    НАСЛЕДУЮТСЯ КЛАССЫ, А НЕ ОБЪЕКТЫ
    НАСЛЕДУЮТСЯ КЛАССЫ, А НЕ ОБЪЕКТЫ

    И медитировать на них каждый день по часу.
    Другими словами -

    НАСЛЕДУЕТСЯ СТРУКТУРА, А НЕ СОСТОЯНИЕ

    чтобы не приходили в голову глупости типа
    мне нужно чтобы $this->test была создана в родителе и уже была в потомке


    Объекты родителя и наследника вообще никак не связаны. Объект родительского класса может быть создан, а может быть и не создан - это никак не отражается на поведении потомка. Инстанс потомка - совершенно самостоятельный объект, который не наследует ничего из состояния родителя.

    Как тебе уже сказали, ты что-то делаешь не так.
    Ответ написан
  • Как оформить вызов методов один за другим?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Суть вопроса абсолютно непонятна.
    Термин "вызов "по цепочке" имеет совершенно определенное значение, которое не имеет ничего общего с вызовом нескольких методов подряд. Это сильно сбивает с толку.

    плюс абсолютно бессмысленный код, который вообще ничего не показывает, даже пресловутый "вызов по цепочке"

    плюс непонятно, в чем конкретно вопрос.
    можно ли в start() написать
    $this->one()
    $this->two()
    $this->three()
    ?

    Можно
    Ответ написан
  • Как разбить на классы?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Учусь рисовать. Интересует, какие краски использовать. Не хочу углубляться в сюжет, просто интересует какие краски нужны.

    Вопрос бессмысленный.
    Ответ простой - никакие классы не использовать. При таком уровне влаения вопросом надо забыть про ооп и сначала научиться структурировать свои мысли, потом свой процедурный код, и потом, когда это наконец станет получаться годиков через пять, классы сами в руки упадут.
    Ответ написан
    Комментировать
  • Для чего объявлять (создавать) имена полей в начале класса если они же по сути объявляются (создаются) в конструкторе?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Зачем мыть руки перед едой, ведь и из грязных ложка не выпадет?

    Пхп - язык с плохой наследственностью. И эта "возможность" - один из рудиментов оставшихся с тех времён, когда язык писался в памперсы.

    Но на самом деле все переменные надо объявлять перед использованием
    Ответ написан
    3 комментария
  • Хорошо ли написан класс БД?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    В целом подход правильный.
    Именно с точки зрения SOLID и сам класс, и его использование спроектированы верно.

    Можно поправить только по мелочам.

    - код соединения никуда не годится. Брать отсюда: Как правильно соединяться с mysql в PDO
    - при этом конфиграцию (хост, пароль, чарсет и прочее) вынести отдельно и передавать в конструктор в виде массива
    - query() переписать так:
    private function query($query, array $params = array()){
        $stmt = $this->db->prepare($query);
        $stmt->execute($params);
        return $stmt;
      }

    - добавить getRow() и использовать в getById именно его.
    - getRows переименовать в getAll чтобы не было путаницы и переписать так
    public function getRows($query, array $params = array(), $mode= PDO::FETCH_ASSOC){
        return $this->query($query, $params)->fetchAll($mode);
      }
    - либо добавить методы для всех методов PDO, либо сделать $db публичной. потому что когда тебе нужно будет выполнить десяток инсертов обернутых в транзакцию, эта обертка превратится в тыкву.
    Ответ написан
    5 комментариев
  • Как соединить работу двух методов?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    1. В контроллере ничего подобного в принципе никогда быть не должно. Ни двух методов, ни одного. Никакой работы с БД в контроллере в принципе быть не может. Контроллер должен только принять данный из формы и вызвать метод модели. Только не убогого класса для маппинга таблицы из БД в класс РНР, который называют моделью новички, а нормальной модели, реелизующей всю бизнес-логику приложения.
    2. По-хорошему, это код для репозитория, поскольку он работает с базой данных. Но конкретная реализация зависит от того как реализован класс customer

    В идеале цепочка вызовов должна быть такая
    Контроллер вызывает инстанс хелпера (или сервиса) CustomerHelper.
    В этот хелпер через конструктор передается инстанс CustomerRepository и присваивается свойству класса.
    В методе Create класса CustomerHelper вызывается метод Create класса CustomerRepository.
    И в этом методе уже и происходит искомая транзакция.
    Ответ написан
    3 комментария
  • Как работать с PDO внутри класса?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Не нужно осваивать всё сразу. У тебя не будет работать тоже все сразу. И ты не будешь знать, что именно.

    Всегда надо решать только одну задачу за раз

    А у тебя тут и ООП, и ПДО, а неймспейсы ,и автолоад, и ни одну из этих вещей ты не понимаешь.

    Собрался писать класс для работы с БД? Отлично, пиши класс для работы с БД. БЕЗ неймспейсов и автолоадов. Не переломишься, добавишь один инклюд. Но зато хотя бы не будешь бегать по коду и искать, в каком из 10 мест у тебя ошибка.

    Только после того, как класс у тебя за заработает, добавляешь неймспейсы. И мучаешься уже с ними.
    После того как заработает с неймспейсами, осваиваешь автолоад.

    Свой велосипед, чтобы он был хоть на что-то годен и добавлял хоть что-то к оригинальному ПДО, переписываешь так
    class DB
    {
        public $pdo;
    
        public function __construct() {
            $host = "localhost";
            $user = "root";
            $password = "";
            $dbname = "dbtest";
            $charset = "utf8";
            
            $dsn = "mysql:host=$host;dbname=$dbname;charset=$charset";
            $this->opt = [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES => FALSE
            ];
            $this->pdo = new PDO($dsn, $user, $password, $opt);
        }
        
        public function query($sql, $args = NULL)
        {
            if (!$args)
            {
                 return $this->pdo->query($sql);
            }
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute($args);
            return $stmt;
        }
        public function __destruct() {
            $pdo = NULL;
        }
    }

    Объяснения по коду (на английском) - Детские болезни моего первого класса для работы с БД

    Дальше.
    Класс Settings не должен наследовать классу БД. Это совершенно разные сущности. Класс человек не должен наследовать классу Карман только потому что у всех людей есть карманы обычно.

    Если человеку нужен карман, то карман передается в конструктор добавляется в свойства класса. Поэтому

    сlass Settings {
        public function __construct($db) {
            this->db = $db;
        }
        public function getSiteName() {
            $stmt = $this->db->query("SELECT Value FROM configs WHERE Name = 'SiteName'");
            return $stmt->fetchColumn();
        }
    }
    Ответ написан
    7 комментариев
  • Что означает $this-> -> в PHP?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    1. Закопать Fuel обратно в его могилу и больше не беспокоить прах этого умершего в далекой древности старца.
    2. Вместо него учить Laravel
    3. Открыть для себя документацию РНР и в непонятных случаях обращаться к ней. В это трудно, конечно, поверить, но там всё написаною Эта ссылка находится в двух кликах по запросу "РНР ООП"

    Честно говоря, я и сам себя часто ловлю на такой "лености мозга". Когда ты 100% можешь сам найти ответ, но спросить у знающего человека проще. но тут важно не поддаваться, и сначала пытаться самостоятельно. Для этого в любом вопросе должна быть фраза - "я искал такм-то", но не нашёл. В процессе написания этой фразы ответ сам и сыщется. В итоге в будет сэкономлено время, приобретён опыт и в интернете будет будет меньше мусора.
    Ответ написан
    4 комментария
  • Стоит ли писать оболочку для PDO?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Нет, не стоит.

    С такой мотивацией ("а не написать ли мне враппер?...") писать вообще ничего не нужно. Потому что ничего хорошего не выйдет.

    Я даже могу точно предсказать, что выйдет: монстр, который многотрудно и многословно дублирует 10% функционала PDO, не добавляя при этом никаких улучшений, и при этом делает невозможным использование остальных 90%.

    Любой код надо писать не от нечего делать, а только имея четкое представление - зачем конкретно этот код нужен, какую конкретно проблему он будет решать.

    Поэтому место написания враппера санчала надо научиться использовать оригинальный ПДО, разобраться с тем, как его правильно использовать, изучить его сильные и слабые стороны, понять, чего вам в нем не хватает, и только потом садиться писать враппер, который добавляет недостающую функциональность, но не урезает при этом существуюущую.
    Ответ написан
    Комментировать
  • Структурирование исключений. Что вы указываете в качестве exeption code?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    В этом вопросе перемешаны мухи и котлеты. Вопрос, вроде бы, про некое "структурирование исключений" (то есть, ждешь про иерархию классов), а на самом деле автора интересует вопрос взаимодействия с пользователями и идентификации ошибок.

    Главная неувязка - какая связь между кодом исключения и уникальным кодом ошибки, служащим для идентификации конкретного места в логах? Это совершенно разные сущности, не имеющие ничего общего. Генерацией уникальных кодов должен заниматься обработчик ошибок, ни ни к кодам исключений, ни к самим исключениями, ни тем более к их иерархии это все не имеет отношения.
    Ответ написан
  • Чистый код: блоки try/catch. Стоит ли так делать?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    > если у нас в try {} несколько понятных вызовов методов,

    причем таких как в примере, далеющих только логирование, и поэтому повторающихся сотни и тысячи раз, то try catch в таеом случае писать не нужно вообще. А добавить либо глобальный трай для всего приложение, либо написать отдельный хендлер/обработчки исключений, если язык позволяет.

    То есть ответ на вопрос очевиден:

    - если у нас в кетче только логинование, то трай не пишем вовсе
    - если в кетче замороченная логика, то трай разумеется имеет смысл вынести в отдельный метод
    Ответ написан
    Комментировать
  • В каком методе определять данные юзера?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Задача решается сильно проще чем ты думаешь.

    Во-первых, тебе не нужно определять юзерагент - он никаким боком не нужен для writeFailedAttempt.
    Тебе не нужен никакой "RealIp". Если ты хочешь записать IP адрес клиента, то ты должен писать в обязательном порядке только $_SERVER['REMOTE_ADDR'] и ничего больше.
    А чтобы обратиться к глобальной переменной никакая функция не нужна.
    Ответ написан
  • Понять принцип работы обьектов в php на примере?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    "Вообщем" учить ООП надо года 2-3 чтобы начало получаться что-то стоящее.
    И в двух строчках тебе на тостере этого не расскажут.

    Покупай учебники, читай. Это единственный вариант, если профильного образования нету.
    Ответ написан
  • Можете что-то подсказать по-поводу кода?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Любой класс, в котором есть метод update() - по определению ущербен.
    попробуй с его помощью сделать банальнейший инкремент поля или использовать функцию Mysql. Не говоря уже о том чтобы выполнить какой-нибудь запрос, отличный от тупого UPDATE.

    Основная проблема твоего кода - его чудовищная уязвимость, дыры просто со всех сторон.

    Вопросы:
    при чем здесь mysqi, если ты пишешь под PDO?
    какие методы работают медленно и с чего ты это взял?
    зачем тебе нужно создать класс для работы с базой данных с драйвером PDO?

    Теперь к ноукам.

    Если говорить об удобстве выполнения запроса UPDATE, то идеальным вариантом будет кастомный плейсхолдер для массива с данными + стандартная функция для выполнения запросов.

    Пример, с использованием phpfaq.ru/safemysql
    Если у нас тупой апдейт
    $db->query("UPDATE ?n SET ?u WHERE id = ?i", $table, $data, $id);

    обращение к этому методу не сложнее, чем к твоему специальному, но при этом любые сложности здесь решаются с легкостью, а у тебя - никак:
    $sql = "UPDATE ?n SET count = count+1, NOW(), ?u WHERE id = ?i";
    $db->query($sql, $table, $data, $id);


    Если все же хочется именно средствами PDO, то читаем тут phpfaq.ru/pdo
    в основном про экранирование имени таблицы и имен полей, и про сборку корректного запроса из пар ключ-значение
    Ответ написан
    2 комментария
  • Зачем нужен ООП?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Объект объективно функциональнее функции.
    Если ты когда-нибудь использовал функции, ты обязательно сталкивался с их неудобствами - невозможностью вернуть больше одного результата, нагромождением параметров, невозможность работать с разным набором параметров и прочее.
    Заменив же функцию на объект, все эти проблемы легко решить.
    Если же ты функций не писал, то надо начать с них.
    Ответ написан
  • Чем отличаются эти две статьи (полиморфизм, PHP)?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    У второго автора батхерт не на тему "что такое полиморфизм", а "о чем статья".
    Он посчитал, что приведенные примеры и нить повествования больше относятся к наследованию, и у читателя не получится различить эти два понятия.

    Сам же последний пример - это нормальная демонстрация полиморфизма, в обоих случаях.
    Ответ написан
    Комментировать
  • Почему после подключения PHP MySQLi класса код перестаёт работать?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Не недо использовать этот класс. Его писал идиот.
    $this->_query = filter_var($query, FILTER_SANITIZE_STRING);

    В одной этой строчке сразу ДВЕ фатальные ошибки.
    плюс отсутствует нормальная обработка ошибок mysql.

    ОМГ
    $this->_mysqli = new mysqli ($this->host, $this->username, $this->password, $this->db, $this->port)
                or die('There was a problem connecting to the database');

    А за такое надо руки отрывать, и пришивать туда, откуда они на самом деле растут.

    Используй вот этот https://github.com/colshrapnel/safemysql
    В нем конечно нет убогого квери билдера, но на самом деле он тебе и не нужен.
    Ответ написан
    1 комментарий
  • Как быстро войти в основы php?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Странный вопрос. Не понимаю, что здесь надо учить?
    Неужели с бэкграундом явы код на РНР не читается как открытая книга?
    По-моему, проблема языка высосана из пальца.

    Если речь о внедрении в рабочий процесс, то это к языку имеет весьма опосредованное отношение к языку.
    Если вопрос по конкретным CMS, то учить надо конкретные CMS - знание языка здесь не поможет.

    Ну и, разумеется, по доброй традиции, все ответы - только на заголовок вопроса. Отвечатели на тостере такие отвечатели.
    Ответ написан
    Комментировать