Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Общие вопросы > Почему статические методы не приветствуются?


Автор: NetJunky 6.10.2012, 14:22
По словам заморских коллег, статические методы не приветствуются в коде. Вопрос почему? Мне привели в пример пару статей, но я не совсем понял из содержания причину такой ненависти к паттерну Singleton и статическим методам в целом.
В статье автор намекает, что стоит придерживаться принципов http://en.wikipedia.org/wiki/SOLID.

Изначально у меня возник вопрос по прчине нужды в классе Util, где я в данный момент имею методы, которы возможно было бы корректнее оформить, как приводится в пример на php.net
Код

class Scalar { 

    /** 
     * 
     * @var mixed 
     */ 
    private $value; 

    /** 
     * 
     * @param mixed $v 
     */ 
    public function __construct($v) { 
        $this->value = $v; 
    } 

    /** 
     * 
     * @return string 
     */ 
    public function __toString() { 
        $v = strval($this->value); 
        return $v; 
    } 

    /** 
     * 
     * @return bool 
     */ 
    public function toBool() { 
        $v = (bool) $this->value; 
        return $v; 
    } 

    /** 
     * 
     * @return float 
     */ 
    public function toFloat() { 
        $v = floatval($this->value); 
        return $v; 
    } 

    /** 
     * 
     * @return int 
     */ 
    public function toInt() { 
        $v = intval($this->value); 
        return $v; 
    } 

    /** 
     * 
     * @return string 
     */ 
    public function toString() { 
        $v = strval($this->value); 
        return $v; 
    } 

}

одно отличие, что у меня они статические и тем самым не используется конструктор и атрибуты класса.

Буду очень признателен за комментарии по данному вопросу.

Автор: ksnk 6.10.2012, 14:48
Цитата(NetJunky @  6.10.2012,  14:22 Найти цитируемый пост)
Мне привели в пример пару статей

Каких, например?

В PHP народ приходит, обычно, имея опыт программирования на других языках. Обычно - Java. Именно оттуда идут многие ООП-предпочтения и правила кодирования, применимость которых в PHP не настолько очевидна и выигрышна как в Java. 

Автор: NetJunky 6.10.2012, 14:52
В данном случае в пример была приведена  статья http://kore-nordmann.de/blog/0103_static_considered_harmful.html. Я изначально беседовал на эту тему на таком сайте, как http://www.stackoverflow.com. Как мне показалось, что люди знают о чём говорят и тем самым у меня возник данный вопрос. Чёткого ответа я там не получил.

Автор: ksnk 6.10.2012, 15:25
Про первый пример (Static dependencies).
Цитата

The code in the class MyWhatEver now has a hard dependency on the FileTool class

Ну и что? Если рассматривать вызов FileTool::recursiveDelete не как работу с классом FileTool, а как вызов  библиотечной функции FileTool::recursiveDelete, то картинка становится не такой криминальной как кажется автору. Никого не смущает наличие толпы маловразумительных функций в самом php? Названия функций, поименованных через двоеточие, imho, несколько более мнемоничны, чем некоторые стандартные.

Второе (Testing) снимается тем-же "взглядом" на статические конструкции. Некоторые вещи просто так сделаны, "не держите их подобным образом"  smile К тому-же есть Mock объекты, которые позволяют изменить даже статические реализации для тестирования.

Добавлено через 4 минуты и 8 секунд
Там, кстати, есть пример "фабрики" от `Daniel O'Connor`, в котором те-же возражения применены для нестаитческой реализации.

Автор: ksnk 7.10.2012, 10:08
Довольно сильное утверждение в статье, про ущербность singleton'а, основанного на типичном статическом механизме.
Обычно, +- декоративные элементы, он выглядит как-то так
Код

class SingleTone_object {

    private static  $instance;

...

   public static function getInstance($args=false) {
        if (self::$instance === null) {  
            self::$instance = new self($args);
        }  
        return self::$instance;
    }
...

}

...

$object=SingleTone_object::getInstance();


Понятно, что такая реализация напрочь исключает возможность использования наследника SingleTone_object без правки кода, иcпользующего его.
Значит ли то, что имеющийся, ущербный в этом смысле, шаблон использования singleTone, свидетельствует об ущербности статических методов как таковых? imho - нет, просто вы(и я  smile ) не умеете их готовить. Давайте использовать более гибкий шаблон singleTone.

К примеру, можно завести специальную статическую переменную в SingleTone_object с сетером, чтобы не поменять ее случайно, в которой будем хранить реальное имя класса, который будем инстанцировать.

Код

class SingleTone_object {

    private static  $instance;
    private static  $className;

...
  // сеттер для className
   public static function redefineClassName($class){
       self::$className=$class;
   }

   public static function getInstance($args=false) {
        if (self::$instance === null) {
            $class=self::$className;
            if(empty($class))  
                 self::$instance = new self($args);
            else
                 self::$instance = new $class($args);
        }  
        return self::$instance;
    }
...

}

// файл NewObject.php
class NewObject extends SingleTone_object{
 ...
}
SingleTone_object::redefineClassName('NewObject');
...
// где-то в коде
$object=SingleTone_object::getInstance();


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

Автор: NetJunky 7.10.2012, 14:57
Небольшое уточнение, вы просто опустили, что конструктор должен быть приватным, так как в данном примере это не затрагивающийся аспект паттерна или в данном случае именно имеется ввиду, что конструктор публичный?

Автор: ksnk 7.10.2012, 16:04
Цитата(NetJunky @  7.10.2012,  14:57 Найти цитируемый пост)
вы просто опустили, что конструктор должен быть приватным

Это как это? Приватных конструкторов в нашей реальности не бывает. Достаточно прогнать тест и убедится что по этому поводу думает php.
Код

class xxx {

   private function __construct() {
      echo 'xxx'; 
   }
  
}

$x=new xxx();


Добавлено через 13 минут и 48 секунд
Хотя нет, бывают...
Код

class xxx {

   private function __construct() {
      echo 'xxx'; 
   }
  
   static function _xxx() {
      return new xxx();
   }
}

$x=xxx::_xxx();


А разве это существенно?

Автор: NetJunky 7.10.2012, 16:18
Имелось в виду, что конструктор Singleton шаблона обычно привытный. Тобишь

Код

class SingleToneObject
{
    /**
     * @var SingleToneObject
     */
    private static $instance;
    
    private function __construct()
    {
    }
    
    public static function getInstance()
    {
        if ( null === self::$instance )
        {  
            self::$instance = new self();
        }
        
        return self::$instance;
    }
}

Автор: ksnk 7.10.2012, 16:21
А, понял. "то такая "защита" для шаблона реализации синглтона? чтобы злые юзеры не вызвали его снаружи противуестественным образом? Хм... забавно, не знал smile

Да. Для моего случая нужно, чтобы конструктор класса-наследника был публичным.

Автор: ksnk 7.10.2012, 21:14
Впрочем, protected вместо public - более кошерно, конечно, и тоже работает.
Код

class xxx {
    private static $class = null;
    private static $instance=null;

    protected function __construct() {
        echo 'xxx '; 
    }

    public static function replaceClass($class){
        self::$class=$class;
    }
  
    public static function getInstance()
    {
        if ( null === self::$instance )
        {  
            if(empty(self::$class))
                self::$instance = new self();
            else {
                $class=self::$class;
                self::$instance = new $class();
            }
        }
        
        return self::$instance;
    }
}

class yyy extends xxx{
   protected function __construct() {
      echo 'yyy '; 
      parent::__construct();
   }
}

xxx::replaceClass('yyy');

$x=xxx::getInstance();

Автор: NetJunky 10.10.2012, 12:30
Вроде более не менее понятно, почему Singleton не приветствуется. Тяжело тестировать. 

Автор: ksnk 10.10.2012, 15:16
Вопросы тестирования, imho, не могут влиять на то, нужно или нет использовать удобное средство. В синглтоне "плохо" то, что расширять его естественным образом - наследованием - сложно. То-же самое относится к использованию статических вызовов self::функций - при переопределении этой функции в наследнике вызывается все равно предыдущий вариант - непривычное и не всегда удобное поведение. 

А с тестированием что-то обязательно придумывают. Вот, к примеру, Reflection заведен, imho, именно в целях тестирования и отладки. Другое дело, что ему тут-же нашлось еще много разных применений...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)