Перегрузка статических методов?

Статус
В этой теме нельзя размещать новые ответы.

PHP_Master

Хранитель порядка
Регистрация
3 Фев 2008
Сообщения
2.639
Реакции
601
Перегрузка динамических методов типа $class->foo()->method() реализуема.
А возможно ли подобное, но только для статических методов (Class::foo(:(:method())?
Перегрузка статических методов доступна в PHP 5.3, но описанный выше вариант у меня реализовать не получается.

PS Просьба подсказки реализовать по типу синглтона не подсказывать :)


Перебранки - личкой, на худой конец во флейме
 
Разве это перегрузка?

Насколько я помню это разименование.
Не знаю как там в 5.3, а в более ранних в принципе такое неосуществимо таким способом.

:: используется для обращения либо внутри класса, либо должно быть известно имя класса (в версии 5.25 и ниже вбитое прямо в код).

Можно всякие финты ушами придумать, типа call_user_func или рефлексию, но вообще то лучше избегать подобного.

Сама необходиость появления такой конструкции должна трактоваться как сигнал к необходимости редизайна системы.
 
Разве это перегрузка?
Ещё один :p
Объясняю популярно - поскольку PHP не является языком со строгой типизацией, перегрузка (в классическом значении этого термина) в нём не осуществима, в PHP перегрузкой называется возможность обращаться к необъявленным свойствам и методам класса.
:: используется для обращения либо внутри класса, либо должно быть известно имя класса (в версии 5.25 и ниже вбитое прямо в код).
Ну имя класса полюбому должно быть известно :D Или есть некий сакраментальный способ создавать инстансы классов незная имени класа?
"::" кроме адресации внутри класса, является способом доступа к статическим свойствам/методам класса без порождения его инстанса.
Можно всякие финты ушами придумать, типа call_user_func или рефлексию, но вообще то лучше избегать подобного.
call_user_func и reflection не имеют ни какого отношения к поднятому вопросу, а что лучше - я уж сам как-нибудь решу.
Сама необходиость появления такой конструкции должна трактоваться как сигнал к необходимости редизайна системы.
Само появление подобного поста должно трактоваться как сигнал к необходимости подтянуть вам матчасть, а потом уж лезть в подобные топики.
Если ты не знаешь для чего может быть полезна конструкция вида $class->foo()->method() и как её использовать, это значит всего лишь, что ты чего-то не знаешь :)

Люди, умоляю, если ничего толково написать не можете, на форуме полно других топиков.
 
Значит хотим холливар? получайте.
Ещё один :p
Объясняю популярно - поскольку PHP не является языком со строгой типизацией, перегрузка (в классическом значении этого термина) в нём не осуществима, в PHP перегрузкой называется возможность обращаться к необъявленным свойствам и методам класса.
Вот именно. Вот это $class->foo()->method() типичный пример разименования. Телепатия не подсказала мне что method не существует. И для перегрузки надо было приводить такой пример: $class->method() и уточнить что вызов идет через __call
Ну имя класса полюбому должно быть известно :D Или есть некий сакраментальный способ создавать инстансы классов незная имени класа?
"::" кроме адресации внутри класса, является способом доступа к статическим свойствам/методам класса без порождения его инстанса.
Не надо мне цитировать мануал. Я вас первый туда ткнул. И прочитайте сами свои слова. А потом смотрите сюда.
Class::foo(:(:method()
Где у вас после вызова foo() известен класс?
call_user_func и reflection не имеют ни какого отношения к поднятому вопросу, а что лучше - я уж сам как-нибудь решу.
Эта задача неосуществима в версии 5.25 простым путем. Или криво, косо можно создать отдаленное подобие с лишним кодом через эти костыли. Можно. Но я уточнил, что не нужно.
Само появление подобного поста должно трактоваться как сигнал к необходимости подтянуть вам матчасть, а потом уж лезть в подобные топики.
Ну ну. Я посмотрю найдется ли человек, который сможет решить то, что вы задумали.
Если ты не знаешь для чего может быть полезна конструкция вида $class->foo()->method() и как её использовать, это значит всего лишь, что ты чего-то не знаешь :)
Эта конструкция так называемая fluent interface (если объект тот же) и также разименование. Эка невидаль. Использую крайне часто. И вы, видимо, хотите такое же к статике применить.
Но это не является допустимым для php 5.25 (выше не знаю). Это заложено в синтаксис языка и кроме новой версии пхп (которая это поддерживает) решения нет.

С таким же успехом можно пытаться сделать приватными методами в php4

зы: интересно, почему сразу такое предвзятое отношение ко мне как к полному тупице в пхп? Из-за ника что ли?
зы2: когда-нибудь вы попробуете TDD и ваше отношение к статическим методам изменится.
 
Не-е-е, холивары мне не нужны :)
Хотя иногда поспорить бывает полезно и поучительно.

Разименование - это другое. Меня интересует, то что в пыхе называется перегрузкой вызова метода.
ОК, попробую объяснить по другому.
Class::foo(:(:method()
Где у вас после вызова foo() известен класс?
foo и есть имя класса: Class::NewClass(:(:methodOfNewClass(). Так понятнее?

Я могу сделать
PHP:
$class = new Class;
$class->NewClass()->methodOfNewClass();
То есть через перегрузку вызова в инстансе $class я могу обратиться к методу другого класса (в нашем случае NewClass).
Вопрос как сделать тоже самое, но со статическими классами.
Но это не является допустимым для php 5.25 (выше не знаю). Это заложено в синтаксис языка и кроме новой версии пхп (которая это поддерживает) решения нет.

С таким же успехом можно пытаться сделать приватными методами в php4
Ну я разве где-то указывал версию :p
Наоборот, подчеркнул про 5.3.
зы: интересно, почему сразу такое предвзятое отношение ко мне как к полному тупице в пхп? Из-за ника что ли?
Тебе показалось.
зы2: когда-нибудь вы попробуете TDD и ваше отношение к статическим методам изменится.
TDD и пользую. Статические методы мне не мешают.
 
Вот это уже нормальный разговор.

Было замечание в стартовом топике, что в 5.3 это работает. Я его еще не пробовал. Мне нет смысла прыгать выше того, что стоит на сервере.

Насколько я помню из мануала конструкция $class->NewClass() если метода нет вызовет __call. В нем можно сделать все что угодно. Главное вернуть обьект у которого и можно вызвать ->methodOfNewClass();

Но дело в том, что экземпляр мы вернуть не можем, раз нам нужен статический метод, а возврат __CLASS__ "Class" ничего не дает. Так что даже поддержка вызова __call для статики ничего не даст.

Более того пхп ругается еще на стадии редактора и выдает заумное название двоеточия при парсинге файла.

Возможно в будущих версиях да, но пока это никак недостижимо.

Хотя для себя я бы, если сильно захотел, мог использовать констркцию Class::foo()->method() с помощью реализации делегатов, дабы не нарушать возможные ограничения пхп.
При этом все равно будет вызван статический метод. И цепочку можно продолжать бесконечно. Class::foo()->method()->bla()->сколько угодно. У меня есть мысль как реализовать.

Устроит вас такой костыль?

зы: А можно узнать по какой причине так необходимо использовать статики, а не объекты?
 
Я рад что мы начали понимать друг друга.
Насколько я помню из мануала конструкция $class->NewClass() если метода нет вызовет __call. В нем можно сделать все что угодно. Главное вернуть обьект у которого и можно вызвать ->methodOfNewClass();

Но дело в том, что экземпляр мы вернуть не можем, раз нам нужен статический метод, а возврат __CLASS__ "Class" ничего не дает. Так что даже поддержка вызова __call для статики ничего не даст.
В 5.3 появился __callStatic, как раз для перегрузки вызова статических методов.
Хотя для себя я бы, если сильно захотел, мог использовать констркцию Class::foo()->method() с помощью реализации делегатов, дабы не нарушать возможные ограничения пхп.
При этом все равно будет вызван статический метод.
У меня были подобные мысли. Но разве foo()->method() не потребует создание инстанса?
Смысл моей затеи в том, чтоб не плодить инстансы там, где без них можно обойтись.

У меня есть мысль как реализовать.
Устроит вас такой костыль?
С удовольствием посмотрю.

PS может всё-таки на "ты"?
 
Потребует создание инстанса делегата.

Но создание такого обьекта это же ерунда. Он выполняется мгновение. Там же почти нет функционала.
Более того можно обойтись всего одним инстансом вспомив о паттерне "сборщик параметров", то есть создать 1 обьект делегата и передавая его использовать. Правда придется в сигнатуре статического метода объявлять дополнительный параметр.

Вот он класс делегат. Я его украл из LIMB и сменил имена для своего проекта
PHP:
class LAF_Delegate
{
  /**
  * @var mixed PHP callback
  */
  protected $php_callback;
  /**
   * @var bool cached validity check result
   */
  protected $is_valid;

  /**
  * Constructor.
  * @param mixed Object which method will be invoked
  * @param string Object method to call
  */
  function __construct($object, $method = null)
  {
    if(is_array($object))
    {
      $this->php_callback = $object;
    }
    else
    {
      if(!$method)
        $this->php_callback = $object;
      else
        $this->php_callback = array($object, $method);
    }
  }

  /**
   * Returns PHP callback
   * @return mixed PHP callback
   */
  function getCallback()
  {
    return $this->php_callback;
  }

  /**
  * Invokes object method with $args
  */
  function invoke()
  {
    if(!$this->isValid())
      throw new LAF_Delegate_Exception("Invalid callback", array('callback' => $this->php_callback));

    $args = func_get_args();
    return call_user_func_array($this->php_callback, $args);
  }

  function invokeArray($args = array())
  {
    if(!$this->isValid())
      throw new LAF_Delegate_Exception("Invalid callback", array('callback' => $this->php_callback));
    return call_user_func_array($this->php_callback, $args);
  }

  function isValid()
  {
    if($this->is_valid !== null)
      return $this->is_valid;
    $this->is_valid = is_callable($this->php_callback);
    return $this->is_valid;
  }

  static function objectify($delegate)
  {
    if(is_object($delegate) && $delegate instanceof LAF_Delegate)
      return $delegate;
    return new LAF_Delegate($delegate);
  }

  /**
  * Invokes all delegates in a list with some args
  * @param array Array of lmbDelegate objects that
  * @param array Invoke arguments
  */
  static function invokeAll($list, $args = array())
  {
    foreach($list as $item)
      $item->invokeArray($args);
  }

  /**
  * Invokes delegates in a list one by one. Stops invoking if delegate return a not null result.
  * @param array Array of lmbDelegate objects
  * @param array Invoke arguments
  */
  static function invokeChain($list, $args = array())
  {
    foreach($list as $item)
    {
      $result = $item->invokeArray($args);
      if(!is_null($result))
        return $result;
    }
  }
}

Это оригинальный класс. Вдруг пригодится.
Можно изменить его так:

Пускай в каждом статическом методе он создаётся и принимает в себя имя нового класса, но без метода и возвращается.
В делегате нужно добавить новый метод
PHP:
  function __call($name, $args = array()){
//тут уже устанавливаем нужный нам метод
...
//и вызываем
	 return $this->invokeArray(args);
//вызывается статический метод и возвращается  новый делегат или можно передать этот и использовать дважды
  }

То есть нужно переделать инициализацию метода да и всего делегата (сложный он больно) и поставить ___ перед всеми методами делегата, чтобы избежать наложения имен методов

Примерно так. Щас ночь на дворе и пробовать уже сил нет.
 
Приблизительно так я и делаю сейчас, но блин так хочется чистой статики :ah: без шаманских плясок.
 
Без шаманских плясок - использовать обьекты.

Я не вижу причин подобного использования статики, кроме минимизации количества обьектов.
Но оно либо нерешаемо, либо решаемо через костыль с делегатами, а значит обьекты все равно создаются.
И. наконец, почему нельзя их создавать? Даже 1000 обьектов это не нагрузка. И если не хочется возиться с "прокси", то отлично помогает отложенная инициализация.

Ничто не мешает так разработке кода, как преждевременная оптимизация. От нее надо бежать как от чумы. Ранее, когда я продумывал все до мелочей, чтобы и быстро и гибко. И это мне вышло боком на 1000% времени увеличив разработку проекта. И в итоге я все равно его с нуля переписал но уже на TDD и не думая о скорости. А заказчик свзял помощнее сервер и оно все летает и так. Мне большой урок.
 
Статус
В этой теме нельзя размещать новые ответы.
Назад
Сверху