За последние 24 часа нас посетили 19999 программистов и 1358 роботов. Сейчас ищут 708 программистов ...

[Library] ModerPDO

Тема в разделе "PHP и базы данных", создана пользователем StulE, 17 авг 2023.

  1. StulE

    StulE Новичок

    С нами с:
    17 авг 2023
    Сообщения:
    7
    Симпатии:
    2
    Все мы знаем, насколько неудобно работать с базами данных, вручную писать запросы, следить за безопасностью (sql-инъекции и тд). Мы решили исправить это, создав библиотеку.

    Описание:
    ModernPDO — это незаменимый инструмент для работы с базами данных. Отличительными особенностями данной библиотеки является простота использования, современный стандарт PHP (8.1), полное покрытие кода тестами, уровень PHPStan'а 9, уровень PSalm'а 1, а также единый стандарт кода.

    Доступный функционал:
    • Поддержка CRUD действий.
    • Поддержка сырых/готовых запросов.
    • Поддержка транзакций.
    Поддерживаемые базы данных:
    • MySQL/MariaDB
    • PostgreSQL
    • SQLite3
    Ссылки:
    Репозиторий на GitHub
    Страница на Packagist
     
    artoodetoo нравится это.
  2. Visman

    Visman Новичок

    С нами с:
    22 апр 2023
    Сообщения:
    12
    Симпатии:
    2
    Адрес:
    Сибирь
    PHP:
    1.         if (!empty($charset)) {
    2.             $pdo->exec('SET NAMES ' . $charset);
    3.         }
    Дальше можно не смотреть.
     
    don.bidon нравится это.
  3. don.bidon

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

    С нами с:
    28 мар 2021
    Сообщения:
    871
    Симпатии:
    135
    Про отсутствие плах на покрытие/тесты на другом форуме отписал.
     
  4. StulE

    StulE Новичок

    С нами с:
    17 авг 2023
    Сообщения:
    7
    Симпатии:
    2
    Описание обновления ModernPDO v3.0.0
    • Убраны create методы в ModernPDO и добавлены Drivers
    • Убрана хардкод установка PDO атрибутов в ModernPDO
    • Добавлена поддержка PDO исключений
    • Переработаны билдеры запросов (добавлен класс Factory)
    • Переписана установка кодировки подключения к MySQL/MariaDB
    • Добавлена плашка code coverage
    • Добавлен класс Escaper для экранирования значений
    • Удалены файлы докера
    • Переписаны интеграционные тесты (для упрощения добавления новых тестов)
    • Переименованы методы Select'а all/one в rows/row
    • Удалены методы Select'а firstBy/lastBy
    • Добавлен трейт Limit для Delete/Select/Update
    • Добавлен трейт OrderBy для Delete/Select/Update
    • Добавлена поддержка joins в Select
    • Добавлена возможность создавать/редактировать/удалять таблицы
    • Добавлена поддержка функций(SUM, COUNT и тд) и условий(IN, BETWEEN и тд) Delete/Select/Update/Insert
    • Добавлена поддержка ключей(Primary, Unique, Foreign) в create/alter table

    Новая версия тык
     
  5. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.761
    Симпатии:
    1.322
    Адрес:
    Лень
    Удобная обвертка, которая запрещает использовать Easy интерфейс:
    PHP:
    1. $statement = $lerma -> query( 'SELECT * ...' );
    2.  
    3. foreach ( $statement AS $row )
    4. {
    5.     // result $row
    6. }
    7.  
    8. // OR
    9.  
    10. iterator_to_array ( $statement );
    PHP:
    1. $values = [
    2.     [ 'name1', 'group1', 'text1' ],
    3.     [ 'name2', 'group2', 'text2' ],
    4.     [ 'name3', 'group3', 'text3' ],
    5. ];
    6.  
    7.  
    8. try
    9. {
    10.     $lerma -> beginTransaction();
    11.  
    12.     // uses rollBack if Exception
    13.     $lerma -> prepare( [ 'INSERT INTO `%s`( `name`, `group`, `text` ) VALUES ( ?,?,? )', 'table' ], $values );
    14.  
    15.     $lerma -> commit();
    16. }
    17. catch ( \Nouvu\Database\Exception\LermaException )
    18. {
    19.  
    20. }
    21.  
    22. // 2 ----------------
    23.  
    24. try
    25. {
    26.     $lerma -> beginTransaction();
    27.  
    28.     $lerma -> prepare( [ 'INSERT INTO `%s`( `name`, `group`, `text` ) VALUES ( ?,?,? )', 'table' ] );
    29.  
    30.     foreach ( $values AS $row )
    31.     {
    32.         $lerma -> execute( $row );
    33.     }
    34.  
    35.     $lerma -> commit();
    36.  
    37.     echo $lerma -> InsertID(); // 3
    38. }
    39. catch ( \Nouvu\Database\Exception\LermaException )
    40. {
    41.     $lerma -> rollBack();
    42. }
    в доке:
    PHP:
    1. <?php
    2. /* Выполнение запроса с передачей ему массива параметров */
    3. $sth = $dbh->prepare('SELECT name, colour, calories
    4.    FROM fruit
    5.    WHERE calories < ? AND colour = ?');
    6. $sth->execute([150, 'red']);
    7. $red = $sth->fetchAll();
    8. $sth->execute([175, 'yellow']);
    9. $yellow = $sth->fetchAll();
    У тебя же автоопределение метода запроса
    https://github.com/StulE-ru/ModernP...9084ddb91c979ec4df6adda/src/ModernPDO.php#L94
    Я юзаю query чтобы юзать prepare. Ничего не напутано ?
    PHP:
    1. $connect = $lerma -> connect() -> get();
    В таком случае единственный правильный выбор падает на:
    PHP:
    1. $mpdo = new ModernPDO(
    2.     pdo: $pdo,
    3. );
    Нет возможности использовать setAttribute
    Нет возможности вывести get_last_insert_id. Что реально его нет, или я его пропустил ? :confused:

    Итого:
    Это обвертка запрещает использовать дальнейшие манипуляции после вызова query метода.
    1. Жесткий фасад
    2. Query builder
    3. Всё
    Если убрать Query builder с библиотеки, то в чем фишка тогда будет ? ;)
    Дебага нет сконструированных запросов.
    --- Добавлено ---
    По опыту скажу: нет никакого смысла юзать queryBuilder, кроме как удобств, потому что, в проектах используют класс со статическим фасадом с запросами. Он обычно находится в Service/Database, либо Model/Database

    PHP:
    1. <?php
    2.  
    3. declare ( strict_types = 1 );
    4.  
    5. namespace App\Service\Database;
    6.  
    7. use Nouvu\Framework\Component\Database\StatementInterface;
    8.  
    9. use function App\Foundation\Helpers\{ config, database };
    10.  
    11. class Alchemy
    12. {
    13.     private const
    14.         ASPECTS_TABLE = 'alchemy_aspects',
    15.         COMPONENTS_TABLE = 'alchemy_components',
    16.         POTIONS_TABLE = 'alchemy_potions';
    17.  
    18.     public static function createTables(): void
    19.     {
    20.         database() -> query( [ '
    21.            CREATE TABLE IF NOT EXISTS %s(
    22.                id INTEGER UNIQUE PRIMARY KEY AUTOINCREMENT,
    23.                name TEXT UNIQUE NOT NULL
    24.            )', config( 'database.prefix' ) . self :: ASPECTS_TABLE ] );
    25.  
    26.         database() -> query( [ '
    27.            CREATE TABLE IF NOT EXISTS %s(
    28.                id INTEGER UNIQUE PRIMARY KEY AUTOINCREMENT,
    29.                name TEXT UNIQUE NOT NULL,
    30.                a1 TEXT NOT NULL,
    31.                a2 TEXT NOT NULL,
    32.                a3 TEXT NOT NULL,
    33.                a4 TEXT NOT NULL
    34.            )', config( 'database.prefix' ) . self :: COMPONENTS_TABLE ] );
    35.  
    36.         database() -> query( [ '
    37.            CREATE TABLE IF NOT EXISTS %s(
    38.                id INTEGER UNIQUE PRIMARY KEY AUTOINCREMENT,
    39.                name TEXT UNIQUE NOT NULL,
    40.                level INTEGER NOT NULL,
    41.                min INTEGER NOT NULL,
    42.                max INTEGER NOT NULL,
    43.                a1 TEXT NOT NULL,
    44.                a2 TEXT NOT NULL,
    45.                a3 TEXT,
    46.                a4 TEXT,
    47.                a5 TEXT
    48.            )', config( 'database.prefix' ) . self :: POTIONS_TABLE ] );
    49.     }
    50.  
    51.     public static function addAspect( string $name ): int
    52.     {
    53.         $a = database() -> prepare(
    54.             [ 'INSERT INTO %s( name ) VALUES ( ? )', config( 'database.prefix' ) . self :: ASPECTS_TABLE ],
    55.             [ $name ]
    56.         );
    57.  
    58.         return $a -> id();
    59.     }
    60.  
    61.     public static function findAspectByName( string $name ): ?object
    62.     {
    63.         return database() -> prepare (
    64.             [ 'SELECT * FROM %s WHERE name = ?', self :: ASPECTS_TABLE ],
    65.             [ $name ]
    66.         ) -> get( StatementInterface :: FETCH_OBJ );
    67.     }
    68.  
    69.     public static function findPotionById( int $id ): ?object
    70.     {
    71.         return database()
    72.             -> query ( [ '
    73.            SELECT t1.id, t1.name, t1.level, t1.min, t1.max, t2.name AS a1, t3.name AS a2, t4.name AS a3, t5.name AS a4, t6.name AS a5
    74.            FROM %s AS t1
    75.            JOIN %2$s AS t2 ON t2.id = t1.a1
    76.            JOIN %2$s AS t3 ON t3.id = t1.a2
    77.            LEFT JOIN %2$s AS t4 ON t4.id = t1.a3
    78.            LEFT JOIN %2$s AS t5 ON t5.id = t1.a4
    79.            LEFT JOIN %2$s AS t6 ON t6.id = t1.a5
    80.            WHERE t1.id = %3$d
    81.        ', self :: POTIONS_TABLE, self :: ASPECTS_TABLE, $id ] )
    82.             -> get( StatementInterface :: FETCH_OBJ );
    83.     }
    84.  
    85.     public static function addComponent( string $name, int ...$aspects ): int
    86.     {
    87.         $a = database() -> prepare(
    88.             [ 'INSERT INTO %s( name, a1, a2, a3, a4 ) VALUES ( ?, ?, ?, ?, ? )', config( 'database.prefix' ) . self :: COMPONENTS_TABLE ],
    89.             [ $name, ...$aspects ]
    90.         );
    91.  
    92.         return $a -> id();
    93.     }
    94.  
    95.     public static function addPotion( string $name, string $level, string $min, string $max, ?int ...$aspects ): int
    96.     {
    97.         $a = database() -> prepare(
    98.             [ "INSERT INTO %s( 'name', 'level', 'min', 'max', 'a1', 'a2', 'a3', 'a4', 'a5' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )", config( 'database.prefix' ) . self :: POTIONS_TABLE ],
    99.             [ $name, ( int ) $level, ( int ) $min, ( int ) $max, ...$aspects ]
    100.         );
    101.  
    102.         return $a -> id();
    103.     }
    104.  
    105.     public static function viewPotions(): array
    106.     {
    107.         return database()
    108.             -> query( [ '
    109.                SELECT t1.id, t1.name, t1.level, t1.min, t1.max, t2.name AS a1, t3.name AS a2, t4.name AS a3, t5.name AS a4, t6.name AS a5
    110.                FROM %s AS t1
    111.                JOIN %2$s AS t2 ON t2.id = t1.a1
    112.                JOIN %2$s AS t3 ON t3.id = t1.a2
    113.                LEFT JOIN %2$s AS t4 ON t4.id = t1.a3
    114.                LEFT JOIN %2$s AS t5 ON t5.id = t1.a4
    115.                LEFT JOIN %2$s AS t6 ON t6.id = t1.a5
    116.            ', self :: POTIONS_TABLE, self :: ASPECTS_TABLE ] )
    117.             -> all( StatementInterface :: FETCH_NUM );
    118.     }
    119.  
    120.     public static function viewAspects(): array
    121.     {
    122.         return database()
    123.             -> query( 'SELECT * FROM ' . self :: ASPECTS_TABLE )
    124.             -> all( StatementInterface :: FETCH_NUM );
    125.     }
    126.  
    127.     public static function viewComponents(): array
    128.     {
    129.         return database()
    130.             -> query( [ '
    131.                SELECT t1.id, t1.name, t2.name AS a1, t3.name AS a2, t4.name AS a3, t5.name AS a4
    132.                FROM %s AS t1
    133.                JOIN %2$s AS t2 ON t2.id = t1.a1
    134.                JOIN %2$s AS t3 ON t3.id = t1.a2
    135.                JOIN %2$s AS t4 ON t4.id = t1.a3
    136.                JOIN %2$s AS t5 ON t5.id = t1.a4
    137.            ', self :: COMPONENTS_TABLE, self :: ASPECTS_TABLE ] )
    138.             -> all( StatementInterface :: FETCH_NUM );
    139.     }
    140.  
    141.     public static function findAspectsByComponent( string $component ): ?array
    142.     {
    143.         return database()
    144.             -> prepare( [ '
    145.                SELECT t2.name AS a1, t3.name AS a2, t4.name AS a3, t5.name AS a4
    146.                FROM %s AS t1
    147.                JOIN %2$s AS t2 ON t2.id = t1.a1
    148.                JOIN %2$s AS t3 ON t3.id = t1.a2
    149.                JOIN %2$s AS t4 ON t4.id = t1.a3
    150.                JOIN %2$s AS t5 ON t5.id = t1.a4
    151.                WHERE t1.name = ?
    152.            ', self :: COMPONENTS_TABLE, self :: ASPECTS_TABLE ], [ $component ] )
    153.             -> get( StatementInterface :: FETCH_NUM );
    154.     }
    155. }
    Шаг и Мат.
    --- Добавлено ---
    Стооооп а где же Enum ?? PHP 8.1 же :(

    PHP:
    1. $lerma = Lerma :: create( driver: DriverEnum :: MySQLi )
    2.     -> setData( host: '127.0.0.1', username: 'root', password: 'root' )
    3.     -> setDatabaseName( dbname: 'dbtest' )
    4.     -> setCharset( charset: 'utf8' )
    5.     -> setPort( port: 3306 )
    6.     -> getLerma();
    PHP:
    1. $lerma = Lerma :: create( driver: DriverEnum :: SQLite3 )
    2.     -> setFile( __DIR__ . '/dbtest.db' )
    3.     -> getLerma();
     
    #5 MouseZver, 4 сен 2023
    Последнее редактирование: 4 сен 2023
  6. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.761
    Симпатии:
    1.322
    Адрес:
    Лень
    Ну да, нема
    Screenshot 2023-09-04 at 11-53-01 Code search results.png
     
  7. StulE

    StulE Новичок

    С нами с:
    17 авг 2023
    Сообщения:
    7
    Симпатии:
    2
    Не вижу смысла отвечать вам по каждому пункту, так как очевидно, что вы пытаетесь хоть кому-то втюхать Lerma (которая никому не нужна, ибо это мем). Но все же, если вдруг кому-то все таки потребуются эти возможности, то ModernPDO крайне гибкая библиотека, которая дает отличную возможность реализовать все его хотелки, используя отличную базу.
     
  8. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.761
    Симпатии:
    1.322
    Адрес:
    Лень
    А причем тут сама Lerma ? Я тебе аргументирую что твой фасад, отделив от queryBuilder, не чем не лучше Простой обвертки
    Хотя погоди, давай теперь по рекламирую все же o_O

    Lerma работает не с PDO, а напрямую с Mysqli, SQLite. Эта библиотека например умеет:
    1. Именованные плейсхолдеры :name для Mysqli ... (без участия mysqli::execute_query)
    2. Генераторы
    3. Вывод результата с сервера без сохранения на клиентской части
    4. Кастомизация и работа напрямую с расширениями
    5. Автоматическое поднятие связи с сервером БД, если отвалился - Для ботоводства.
    6. Мульти-добавление значений INSERT`ом через астрал, вместо 100500 ( ?, ?, ?, ..... и т.д. )
    Всё это делал не для продакшен.
    В каком месте гибкая ? В жестком фасаде, или конструктор query ? Уточняй уж.
     
    #8 MouseZver, 4 сен 2023
    Последнее редактирование: 4 сен 2023
  9. StulE

    StulE Новичок

    С нами с:
    17 авг 2023
    Сообщения:
    7
    Симпатии:
    2
    Я не хотел и не хочу вам что-то доказывать, но как метко подметил мой друг, адекватные люди могут вам поверить.
    Так что поехали, вы сами этого захотели...

    > А причем тут сама Lerma ?
    При том, что примеры написаны на ней, а значит вы говорите, что она лучше, чем ModernPDO, что в корне неверно.

    > Я тебе аргументирую что твой фасад
    Не увидел в ваших нарциссических потугах аргументов.

    > отделив от queryBuilder, не чем не лучше Простой обвертки
    Резать либу пополам и чему-то удивляться... Но даже удалив все Actions и тд, это все равно будет лучше, чем ваша либа.

    > Мем который умеет
    Вы - большой молодец, продолжайте в том же духе нахваливать себя за накопленный в течение 5+ лет функционал, который никому кроме вас не нужен.
    А если серьезно, то это мем хотя бы потому, что вас просили написать тесты в 2017 году, на эту просьбу вы плевали с высокой колокольни, закончим тем, что репозиторий оформлен ужасно, код оформлен ужасно, адекватного тестирования до сих пор нет, при этом всем ваш код максимально не расширяемый, как мне, как пользователю, который вдруг юзает вашу либу, добавить поддержку других субд и еще много чего, что мне банально лень писать, так как вы все равно это исправлять не будете.

    > В каком месте гибкая ? В жестком фасаде, или конструктор query ? Уточняй уж.
    Понимаю, сложно понять в чем библиотека гибкая, особенно когда это написано в README

    upload_2023-9-4_23-6-35.png

    Пишите о том: где я неправ, что можно сделать лучше и тд. Не надо писать об отсутствии чего-то, что можно легко добавить.
     
  10. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.761
    Симпатии:
    1.322
    Адрес:
    Лень
    Я не понял. Тебя смутило названия переменных или о том где стоял вопрос "Где Enum ? который был завезен в php 8.1" ?? и в качестве примера, привел реализацию со своего кода. У меня длиннее если что.

    А теперь перейдем к главному.
    Если про простую обвертку, то огорчу тебя. Она не моя, а от форумного сообщества PHPClub. И то что ты фасад по БД разбил на мелкие классы, то в скомпонованном виде и по функциональной части, она будет абсолютно одинакова с Простой обверткой, не более. Но кричать что твоя лучше и тем более в продакшен лепить - это как слепо-верующий фанатик, который только что открыл мир для себя, забыв что давно за тебя уже всё написали, в просторах Github выложено, действительно, уж более получше, по могучее будет инструмент, чем какой-то велосипед от какого-то Петьки.

    По функционалу и гибкости.
    Давай начнем по списку с Генераторов/Итераторов. В PDO есть уникальная способность как и в MySQLi, выводить результат запросов напрямую через итерацию циклов. Она хоть и не документированная, поэтому о ней мало кто знает.
    Знакомься: PDOStatement::getIterator самый быстрый способ по выводу.
    Пример:
    PHP:
    1. $stmt = $pdo -> prepare( 'SELECT * FROM table WHERE name = :name' );
    2.  
    3. $stmt -> execute( [ 'name' => $name ] );
    4.  
    5. foreach ( $stmt AS $result )
    6. {
    7.     // Iterations...
    8. }
    Видишь? я не использую fetch fetchAll.
    А у твоей библиотеки $statement переходит в твой фасад, где логика кода отсутствует по итераторному выводу, а именно тут.
    Т.е. не я, не вася не сможет использовать данный аспект. Но тут ты выходишь со своим аргументом, что якобы можно будет расширить/дополнить функционал. Отлично, попробуем ?
    Значит так, чтобы нативный $statement использовать, мне нужно переписать Statement.php, но его использует Factory.php его тоже переписывать, и пошло и поехало. Итого от и до переписывать придется.
    Петь, ты об интерфейсах слышал ? Если были бы у тебя типы данных с использованием интерфейсов, то все бы смогли решить половину вопросов. Выучи для чего паспорта такие.


    Так же и об подготовительных запросах. Пишу:
    PHP:
    1. $stmt = $pdo -> prepare( 'INSERT .... VALUES ( ?,?,? )' );
    2.  
    3. foreach ( $results AS $send )
    4. {
    5.     $stmt -> execute( $send );
    6. }
    Здесь я смогу сколько угодно данных отослать в поток.
    Что у тебя ? будет запрос такого формата:
    PHP:
    1. $stmt = $pdo -> prepare( 'INSERT .... VALUES ( ?,?,? ),
    2. ( ?,?,? ),
    3. ( ?,?,? ),
    4. ( ?,?,? ),
    5. ( ?,?,? ),
    6. ( ?,?,? ),
    7. ( ?,?,? ),( ?,?,? ),( ?,?,? ),.....' );
    Супер ? Пупер. Опять переписывать, делать форк и что остается ? Какой смысл использовать твою библиотеку ? Ради QueryBuilder ?
    Так их полным полно и на много лучше чем твой - это факт. ( Я не занимаюсь писькомерством ).

    Поэтому аргументирую, почему я называю это жестким фасадом.

    Начни воспринимать критику к своему говнокоду, а не как к личности, которая побежала по всем моим сообщениям, выяснять где и кому рекомендую(нет) Свой длинный инструмент с мемами. Мне поxуй до того момента, пока это кому-то станет действительно нужным.

    Начни с этого:
    PHP:
    1. public function getInstance(): \PDO
    2. {
    3.     return $this -> pdo;
    4. }
     
    don.bidon нравится это.
  11. StulE

    StulE Новичок

    С нами с:
    17 авг 2023
    Сообщения:
    7
    Симпатии:
    2
    Извините, что токсично ответил в предыдущих комментариях, мне тогда показалось, что вы хотите просто попиарить свой продукт и посраться.

    > Где Enum ? который был завезен в php 8.1
    Не вижу смысла его использовать в моей либе, так как они накладывают ограничения на изменения, и без правки кода либы ничего расширить нельзя (добавить новый драйвер и тд).

    > Нет того и того в плане поддержки pdo.
    Да - много чего нет. На другом форуме мне уже объяснили, что либа в текущем варианте = query builder + простая обертка над pdo, при этом одно наслоилось на другое, в следующей версии исправлю. По факту вы говорите тоже самое, только из-за формы подачи я этого сразу не понял.

    Отвечаю на частые вопросы:
    Название ModernPDO потому, что так исторически сложилось, от PDO только название и самая простейшая обертка.
    Большой акцент идет на интерфейс к базам данных (в простонародье query builder).
    Почему этим должны пользоваться - я не знаю, я выложил это в open source потому, что сам использую в 2х проектах (другие варианты не подошли)
    Против критики я ничего не имею, наоборот, считаю крайне полезной.
    Планирую дальше развивать эту либу (явно разделить на PDO и query builder, добавлять поддержку новых бд и тд), и в будущем на основе этого сделать простую orm (мне несколько людей сказали, что это уже может кому-то реально помочь, а не упростить синтаксис)
     
  12. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.761
    Симпатии:
    1.322
    Адрес:
    Лень
    Найди ошибку

    2023-09-11_00-07-27.png
    --- Добавлено ---
    Какое ограничение ?
    --- Добавлено ---
    Я писал об смысла использования любого query конструктора нет, кроме удобств. Т.к. это всё оформляется в статическом классе и ты сразу видишь что и почем, чем потом дебажить "что там получилось?". А это уже ни хрена не удобство.
     
  13. StulE

    StulE Новичок

    С нами с:
    17 авг 2023
    Сообщения:
    7
    Симпатии:
    2
    > Найди ошибку
    Connect to?

    > Какое ограничение ?
    На безболезненное добавление новых бд и тп, с enum у вас прописан жесткий список в коде либы, а с использованием наследования и new MySQL/PostgreSQL и тд, ничего не мешает пользователю добавить class DB extends ModernPDO и тд + если есть список, то его нужно обрабатывать (иначе как получать объекты?) А это все в случае добавления придется менять, то есть помимо того, чтобы дописать новый(е) классы приходится менять код либы, а это не круто
     
  14. don.bidon

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

    С нами с:
    28 мар 2021
    Сообщения:
    871
    Симпатии:
    135
    initiAlize ))) Шторм словарь английский по умолчанию имеет, остальные подгружать может.
     
  15. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.761
    Симпатии:
    1.322
    Адрес:
    Лень
    В общем, код с интерфейсами ожидаю. Тогда можно будет об расширении говорить.
    https://www.php.net/manual/en/language.enumerations.methods.php
    --- Добавлено ---
    На Enum не давлю. Вопрос был из-за возможности в php 8.1
     
  16. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.761
    Симпатии:
    1.322
    Адрес:
    Лень
    Спустя 2 месяца с воздержанной отметкой скачиваний библиотеки (428), я могу абсолютно заверить об самонабивания статистики для лживого показателя "интереса" программистов к данному репозиторию.
     
  17. StulE

    StulE Новичок

    С нами с:
    17 авг 2023
    Сообщения:
    7
    Симпатии:
    2
    Вы правы лишь отчасти. Действительно, у программистов библиотека не вызвала какого-то интереса, но я никогда не преследовал цели показать "лживый интерес", так же как и не кичился этими скачиваниях.

    Скачивания берутся с packagist, который в свою очередь считает скачиванием любой composer install, поскольку я использовал библиотеку в нескольких проектов, которые стабильно обновлялись, соответственно установок было много, в какой-то момент проекты перестали обновляться, а значит и показатель замер на 428 скачиваниях.
     
    MouseZver нравится это.