Статический инициализатор классов в PHP - PullRequest
83 голосов
/ 22 июля 2010

У меня есть вспомогательный класс с некоторыми статическими функциями.Все функции в классе требуют, чтобы «тяжелая» функция инициализации запускалась один раз (как если бы это был конструктор).

Есть ли хорошая практика для достижения этой цели?

Единственное, что яМысль о том, чтобы вызвать функцию init и прервать ее поток, если она уже была запущена один раз (с использованием статического $initialized var).Проблема в том, что мне нужно вызывать его для каждой функции класса.

Ответы [ 7 ]

107 голосов
/ 22 июля 2010

Звучит так, как будто бы вам лучше обслужить синглтон, а не набор статических методов

class Singleton
{
  /**
   * 
   * @var Singleton
   */
  private static $instance;

  private function __construct()
  {
    // Your "heavy" initialization stuff here
  }

  public static function getInstance()
  {
    if ( is_null( self::$instance ) )
    {
      self::$instance = new self();
    }
    return self::$instance;
  }

  public function someMethod1()
  {
    // whatever
  }

  public function someMethod2()
  {
    // whatever
  }
}

А затем, при использовании

// As opposed to this
Singleton::someMethod1();

// You'd do this
Singleton::getInstance()->someMethod1();
92 голосов
/ 22 июля 2010
// file Foo.php
class Foo
{
  static function init() { /* ... */ }
}

Foo::init();

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

55 голосов
/ 23 июля 2010

На самом деле, я использую открытый статический метод __init__() в своих статических классах, которые требуют инициализации (или, по крайней мере, должны выполнить некоторый код). Затем в моем автозагрузчике, когда он загружает класс, он проверяет is_callable($class, '__init__'). Если это так, он вызывает этот метод. Быстро, просто и эффективно ...

2 голосов
/ 12 апреля 2019

ПРИМЕЧАНИЕ: Это именно то, что OP сказал, что они сделали. (Но не показал код для.) Я показываю здесь детали, чтобы вы могли сравнить их с принятым ответом. Я хочу сказать, что оригинальный инстинкт OP был, ИМХО, лучше, чем ответ, который он принял.


Учитывая, насколько высоко оценен принятый ответ, я хотел бы отметить, что "наивный" ответ на одноразовую инициализацию статических методов едва ли больше кода, чем та реализация Singleton - и имеет существенное преимущество .

final class MyClass  {
    public static function someMethod1() {
        MyClass::init();
        // whatever
    }

    public static function someMethod1() {
        MyClass::init();
        // whatever
    }


    private static $didInit = false;

    private static function init() {
        if (!$didInit) {
            $didInit = true;
            // one-time init code.
        }
    }

    // private, so can't create an instance.
    private function __construct() {
        // Nothing to do - there are no instances.
    }
}

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

MyClass::someMethod1();

Сравните это с вызовами, требуемыми для принятого ответа:

MyClass::getInstance->someMethod1();

Как правило, лучше всего платить кодирование один раз, когда вы кодируете класс, чтобы сделать звонящих проще.


Из всех ответов (включая этот) я предпочитаю ответ Виктора Николь . Просто. Никакого дополнительного кодирования не требуется. Нет "продвинутого" кодирования, чтобы понять. (Я рекомендую включить комментарий FrancescoMM, чтобы "init" никогда не выполнялся дважды.)

Так что я не потрудился написать этот ответ. Но так много людей проголосовали за принятый ответ, что я заключаю, что некоторые люди просто не знают об очевидном, «наивном» подходе (который я показываю здесь). Поймите это как отправную точку.

2 голосов
/ 10 сентября 2018

Есть способ вызвать метод init() один раз и запретить его использование, вы можете превратить функцию в приватный инициализатор и вызвать его после объявления класса следующим образом:

class Example {
    private static function init() {
        // do whatever needed for class initialization
    }
}
(static function () {
    static::init();
})->bindTo(null, Example::class)();
0 голосов
/ 15 января 2018

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

<?php

class LanguageUtility
{
    public static function initializeClass($class)
    {
        try
        {
            // Get a static method named 'initialize'. If not found,
            // ReflectionMethod() will throw a ReflectionException.
            $ref = new \ReflectionMethod($class, 'initialize');

            // The 'initialize' method is probably 'private'.
            // Make it accessible before calling 'invoke'.
            // Note that 'setAccessible' is not available
            // before PHP version 5.3.2.
            $ref->setAccessible(true);

            // Execute the 'initialize' method.
            $ref->invoke(null);
        }   
        catch (Exception $e)
        {
        }
    }
}

class MyClass
{
    private static function initialize()
    {
    }
}

LanguageUtility::initializeClass('MyClass');

?>
0 голосов
/ 14 июня 2016

Примечание - RFC, предлагающий это, все еще находится в черновом состоянии.


class Singleton
{
    private static function __static()
    {
        //...
    }
    //...
}

предлагается для PHP 7.x (см. https://wiki.php.net/rfc/static_class_constructor)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...