Поругайте Static wrapper

Фанат

oncle terrible
Команда форума
Как вы знаете, я не слишком силён в оопе.
Код цельнотянутый у Никиты Попова из его ПДО враппера трехгодичной давносте.

PHP:
class DB
{
    protected static $instance = null;

    final private function __construct() {}
    final private function __clone() {}

    public static function instance($cfg = array())
    {
        if (self::$instance === null)
        {
            require dirname(__FILE__)."/safemysql.class.php";
            self::$instance = new safemysql($cfg);
        }
        return self::$instance;
    }
  
    public static function __callStatic($method, $args)
    {
        return call_user_func_array(array(self::instance(), $method), $args);
    }
}
Что здесь плохого и надо ли его улучшить или так сойдёт?

Я знаю, многие сделали свой. Делитесь, если не жалко
 

riff

Новичок
PHP:
    public static function instance($cfg = array())
    {
        if (self::$instance === null)
        {
            require dirname(__FILE__)."/safemysql.class.php";
            self::$instance = new safemysql($cfg);
        }
        return self::$instance;
    }
1. DB::instance(с параметрами) позволено вызывать один раз, в последствии только без параметров. Поэтому instance(с параметрами) должен быть обязательно однажды объявлен, следовательно его будут выносить в раздел загрузки. Без этого дальнейшая работа бессмысленна, более того чревата ошибками: например, не подключил я instance(с параметрами), но начал пользоваться instance(), добрый DB мне его создаст, но не тот что нужен, а будет создан с параметрами по-умолчанию.

2. DB::instance() - не понятно, что я создаю: по идее класс DB, а на самом деле safemysql.
Например, создам я "class My_DB extends DB" с нужными мне "public function", радостный напишу "My_DB::instance()->my_function" и получу ошибку.

Поэтому "instance($cfg)" я бы переименовал в типа "create_safemysql($cfg)", для вызова её единожды в автозагрузке (при запуске проекта).
А "publuc static $instance" переименовал бы в "public static $safemysql" и соответственно в коде писал бы DB::$safemysql->query(...).
 
Последнее редактирование:

riff

Новичок
И ещё, Фанат, я бы посоветовал не писать класс DB. А остановиться на safemysql. Дальше "я" (как пользователь) сам создам нужный мне DB, и в нём инициализирую safemysql, (например в функции коннекта к базе). Зачем ты его(DB) пишешь?
 
Последнее редактирование:

HraKK

Мудак
Команда форума
А зачем, вообще, делать DB звездным объектом?
 

Вурдалак

I'd like to model your domain
Потому что Фанат, так сказать, старой закалки. Проще дернуть статический метод и "немного" поговнокодить, нежели юзать какие-то навороченные и заумные best practices, которые придумали от большого ума. Мол, все равно DB в 95% будет синглтоном, в жопу пошли остальные 5%.
sheldon_sarcasm.jpg
 

WMix

герр M:)ller
Партнер клуба
твоя идея это запись типа DB::getOne('select version()'), если я правильно понимаю. ограничения думаю тебе известны, всего одна база. а выгрыш простота и досигаемость отовсюду.
если строчку слегка удленить, Db::getAdapter($name)->getAll('select version()') то решается и досигаемость и различные драйвера и множество connections в одном проекте и на модель определенный адаптер про который модель ничего не знает.
Это можно добавить после (не переписывая программу), ожидая от краткой записи некий "default adapter", а от длинной - специфический.
только придумать способ добавлять новые драйвера (описать driver-interface), connections, а также свободу выбора "default adapter"
до тех пока не существует перечисленного, у разработчика взявшего твою библиотеку при появлении одной из задач, не остается выбора, кроме как (пере/до)писать твой класс самому, а значит забыть о обновлениях твоей ветки.
 
Последнее редактирование:

Фанат

oncle terrible
Команда форума
Ну вообще Вурдалак отчасти прав.
Но в основном - постоянно спрашивают статику. Для классическогоговнокода уж очень она удобна.
 

Тугай

Новичок
Код идеален, но можно похоливарить про instance() и getInsatace() :)
Как бы instance() ближе к micisofoft, а getInsatace() к unix )))
 

Фанат

oncle terrible
Команда форума
Покажи пример кода с работой с тремя базами.
Это очень хороший вопрос.

Во-первых, стандартный ответ на него - это
PHP:
$db1 = new safemysql();
$db2 = new safemysql();
DB::instance();
Но интереснее, конечно же, сделать поддержку теми же синглетонами.
Вот что у меня получилось, опять же, методом тупой копипасты:
PHP:
class DB
{
    protected static $instance = array();

    final private function __construct() {}
    final private function __clone() {}

    public static function instance($cfg = array())
    {
        $className = get_called_class();
        if(!isset(self::$instance[$className]))
        {
            require_once dirname(__FILE__)."/safemysql.class.php";
            self::$instance[$className] = new safemysql($cfg);
        }
        return self::$instance[$className];
    }
 
    public static function __callStatic($method, $args)
    {
        return call_user_func_array(array(self::instance(), $method), $args);
    }
}
class DB2 extends DB {}
DB2::query("set @aaa:=1");
echo DB::getOne('SELECT @aaa');
echo DB2::getOne('SELECT @aaa');
Я, кстати, давно уже мечтал делать ЭТО екстендом.
 

Absinthe

жожо
> Я, кстати, давно уже мечтал делать ЭТО екстендом.

Кажется очень грязным кодом.
 

Absinthe

жожо
Расширение класса должно дополнять (Лисков) принцип работы класса.
Тут же это делается как копипаста, засахаренная синтаксисом 5.3. Новой логики не добавляется.

А если 11 баз, будем заводить новых 11 файлов с разными классами?
А если несколько баз будут иметь одну и ту же структуру и надо будет между ними выбирать?
 

Вурдалак

I'd like to model your domain
Фанат, у тебя есть некий объект, который зависит от базы данных, неважно от какой. Ты туда хардкодишь DB, а потом в какой-то момент понимаешь, что было бы круто, чтобы зависимость была от safemysql, а не DB (DB2, ...), но внезапно ты осознаешь, что ты увлекся своими синглтонами и просто так заинжектить уже не выйдет.

Что только не придумают, лишь бы не юзать DI.
 

WMix

герр M:)ller
Партнер клуба
PHP:
class UsersService{
// ...
public function getById($id){
  return new User (
    DB::getRow( // тут захардкодили. класс UsersService, придется переписывать для другой базы
      'select * from users ...', $id
    )
  );
}
}
 

Фанат

oncle terrible
Команда форума
Зачем новый файл для одной строчки?

Вообще, я не думал углубляться в дискуссию "чем плох синглетон".
 
Сверху