За последние 24 часа нас посетили 36754 программиста и 7752 робота. Сейчас ищут 1760 программистов ...

Подключение базы внутри функции

Тема в разделе "PHP для новичков", создана пользователем Vladd55, 14 фев 2023.

  1. Vladd55

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

    С нами с:
    11 дек 2021
    Сообщения:
    88
    Симпатии:
    1
    Подключение к базе данных происходит вот так:
    Код (Text):
    1. $db = mysqli_connect(BD_HOST, BD_LOG, BD_PASS, BD_NAME) or die('Ошибка подключения к БД');
    Потом в теле файла имеется несколько запросов к базе; все нормально работает.

    Но еще есть функция вывода комментариев. Она очень громоздкая, и приводить ее полностью нет смысла. Проблема в том, что в эту функцию я хочу добавить запрос к базе, и возникает проблема.

    Код (Text):
    1.           function comments(array $comments, $level = 0, $next = 0, $arr = array())
    2.           {
    3.  
    4. // Здесь всякие логические операции без обращения к базе.
    5.  
    6. // А это мой запрос к базе
    7. query = mysqli_query($db, "SELECT `id` FROM `comment` WHERE `id` = 157");
    8.           }
    9.  
    10.           comments($comments);
    Диагностическое сообщение:
    <b>Notice</b>: Undefined variable: db in <b>/home/b/comment-text.php</b> on line <b>94</b><br />
    <br />
    <b>Warning</b>: mysqli_query() expects parameter 1 to be mysqli, null given in <b>/home/b/comment-text.php</b> on line <b>94</b><br />

    94 - это и есть строка моего запроса.

    Я понимаю, что $db не попадает в область видимости переменных функции. А как её туда "запихнуть"?
     
  2. Vladd55

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

    С нами с:
    11 дек 2021
    Сообщения:
    88
    Симпатии:
    1
    Подключил через параметры функции. Это нормально?
    Код (Text):
    1. function comments($db, array $comments, $level = 0, $next = 0, $arr = array())
    2.  
    3. comments($db, $comments);
     
  3. don.bidon

    don.bidon Активный пользователь

    С нами с:
    28 мар 2021
    Сообщения:
    947
    Симпатии:
    147
    Лучше так, чем через global/$GLOBALS.
     
    Vladd55 нравится это.
  4. Vladd55

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

    С нами с:
    11 дек 2021
    Сообщения:
    88
    Симпатии:
    1
    А передавать $db через сессию нельзя?
     
  5. don.bidon

    don.bidon Активный пользователь

    С нами с:
    28 мар 2021
    Сообщения:
    947
    Симпатии:
    147
    @Vladd55, даже если получится (почему сам не попробовал?), это жёсткое извращение, сессии не для этого.
     
    Vladd55 нравится это.
  6. Vladd55

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

    С нами с:
    11 дек 2021
    Сообщения:
    88
    Симпатии:
    1
    Конечно же, я попробовал. Но я исхожу из того, что не все, что заработало, правомерно использовать. Поэтому нетиповые ситуации уточняю.

    А global/$GLOBALS мне как-то сильно не по вкусу. Других же штатных вариантов нет?
     
  7. don.bidon

    don.bidon Активный пользователь

    С нами с:
    28 мар 2021
    Сообщения:
    947
    Симпатии:
    147
    Обернуть в класс, в конструкторе задать свойство $db, из других методов обращаться к нему, если чуть менее сложно. И да, с глобальной областью видимости вообще экспериментировать плохо.
     
    Vladd55 нравится это.
  8. mkramer

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

    С нами с:
    20 июн 2012
    Сообщения:
    8.497
    Симпатии:
    1.726
    Для процедурного кода какое-то количество глобальных переменных норма.
     
    miketomlin нравится это.
  9. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.861
    Симпатии:
    656
    Как выше написали, для процедурки норм. предопределенные глоб. переменные. (НЕ «предопределенные», т.е. переменные для собвенных нужд фронта, тоже норм.) Ну, если сильно хоЦА, можешь загнать в какой-нить синглтон, общую переменную реестра или какую-нибудь спец. переменную (чтобы к ней обращаться через спец. ф-цию вроде db()). В G-Drive, например, использовали глоб. переменную $link (она считается параметром контроллера; потом ее можно самому куда-нить загнать под соотв. модель и т.п., если надо). В более «взрослых» фронтах – соответственно более «взрослые» подходы.
    --- Добавлено ---
    Для моделей на процедурке там обычно так: контроллер вызывает ф-цию модели без передачи $link, та библиотечную ф-цию для работы с БД без передачи $link, а библиотечная ф-ция обращается напрямую к global $link.
    --- Добавлено ---
    Еще иногда у ф-ций моделей и библиотечных ф-ций для работы с БД бывает дефолтный параметр $link='link', чтобы можно было делать так: $GLOBALS[$link] (не путать с $GLOBALS['link']). Но по-моему это изврат. Проще значение глоб. переменной подменять, если нужно работать сразу с несколькими объектами mysqli.
    --- Добавлено ---
    Нет никакой обработки ошибок? Ф-ции-обертки для работы с БД используются не просто, как абстрактный слой, а еще и исключения при ошибках генерируют ;)

    Это тоже фигня. Нужно 503-юю выдавать ;) И еще вот что: https://gency.ru/comment/116 (кодировку можно не хардкодить, а тоже из конфиг. параметра брать).
     
    #9 miketomlin, 15 фев 2023
    Последнее редактирование: 15 фев 2023
  10. don.bidon

    don.bidon Активный пользователь

    С нами с:
    28 мар 2021
    Сообщения:
    947
    Симпатии:
    147
    Весело тесты писать, когда окружение в глобалох-то )
     
    miketomlin нравится это.
  11. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.861
    Симпатии:
    656
    Как-то пишут :)
     
  12. Drunkenmunky

    Drunkenmunky Старожил

    С нами с:
    12 авг 2020
    Сообщения:
    1.511
    Симпатии:
    284
    Не надо ничего запихивать.
    Измените общий подход, разбив скрипт пошагово.
    У вас есть: подключение к базе, составление запроса к ней, и обработка вывода.
    Ни один из шагов не требует запихивания.
     
  13. JohnWarner

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

    С нами с:
    16 ноя 2022
    Сообщения:
    29
    Симпатии:
    2
    Автору.
    Напишите или подключите готовый движок работы с базой.
    Сможете тогда юзать его где угодно на сайте.
     
  14. artoodetoo

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

    С нами с:
    11 июн 2010
    Сообщения:
    11.129
    Симпатии:
    1.223
    Адрес:
    там-сям
    @Vlad55
    Можно написать функцию или статический метод класса, которая/ый будет возвращать соединение с базой. В отличие от переменных, функции тебе доступны в любом месте. Еще тебе в копилку — переменные, объявленные со словом static, сохраняются в последующих вызовах.

    PHP:
    1. function db()
    2. {
    3.   static $db = null;
    4.   return $db ?? $db = mysqli_connect(...); // функция будет вызвана только один раз!
    5. }
    6.  
    7. // ...
    8.  
    9. $result = mysqli_query(db(), "SELECT ...");
    Как временное решение потянет. Постепенно ты придешь к пониманию что процедурный подход неудобен, начнешь использовать классы, и будешь инжектить все нужные зависимости.
    --- Добавлено ---
    https://www.php.net/manual/ru/language.variables.scope.php#language.variables.scope.static
     
  15. ibnteo

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

    С нами с:
    30 сен 2008
    Сообщения:
    34
    Симпатии:
    1
    Так как в PHP объекты не долго живут, удобнее использовать статические методы и переменные класса. Их так же удобно вызывать как и функции, и не нужны глобальные переменные для хранения подключения к базе данных.
    PHP:
    1. class DB {
    2.     private static $con = null;
    3.     private static function con() {
    4.         if (! self::$con) {
    5.             self::$con = mysqli_connect(...);
    6.         }
    7.         return self::$con;
    8.     }
    9.     static function query($sql) {
    10.         return mysqli_query(self::con(), $sql);
    11.     }
    12. }
    13. $comment = DB::query("SELECT `id` FROM `comment` WHERE `id` = 157");
    Плюс такого подхода ещё и в том, что подключение к базе данных происходит лишь при первом SQL-запросе, а если запросов не было при вызове какой-нибудь страницы, то и не будет впустую подключаться к базе данных.

    Вместо mysqli посмотри на использование PDO, работающий одинаково с разными базами данных, и где можно безопасно и удобно передавать параметры в SQL, что-то вроде такого:
    PHP:
    1. $comment = DB::query("SELECT * FROM comment WHERE id=?", [$id]);
     
  16. don.bidon

    don.bidon Активный пользователь

    С нами с:
    28 мар 2021
    Сообщения:
    947
    Симпатии:
    147
    Повставляй логгирование в деструкторы и удивись )))
    Да и вообще, если есть класс App, в котором всё запускается, живут все замечательно.