program story

PHP의 정적 클래스 이니셜 라이저

inputbox 2020. 9. 20. 09:46
반응형

PHP의 정적 클래스 이니셜 라이저


일부 정적 함수가있는 도우미 클래스가 있습니다. 클래스의 모든 함수는 생성자 인 것처럼 한 번 실행하려면 '무거운'초기화 함수가 필요합니다.

이를 달성하기위한 좋은 방법이 있습니까?

내가 생각한 유일한 것은 init함수를 호출 하고 이미 한 번 실행 된 경우 (정적 $initializedvar 사용) 흐름을 끊는 것 입니다. 문제는 클래스의 모든 함수에 대해 호출해야한다는 것입니다.


여러 정적 메서드보다 싱글 톤이 더 나은 서비스를 제공하는 것 같습니다.

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();

// file Foo.php
class Foo
{
  static function init() { /* ... */ }
}

Foo::init();

이렇게하면 클래스 파일이 포함될 때 초기화가 수행됩니다. 자동로드를 사용하여 필요할 때만 (한 번만)이 작업이 수행되도록 할 수 있습니다.


Actually, I use a public static method __init__() on my static classes that require initialization (or at least need to execute some code). Then, in my autoloader, when it loads a class it checks is_callable($class, '__init__'). If it is, it calls that method. Quick, simple and effective...


NOTE: This is exactly what OP said they did. (But didn't show code for.) I show the details here, so that you can compare it to the accepted answer. My point is that OP's original instinct was, IMHO, better than the answer he accepted.


Given how highly upvoted the accepted answer is, I'd like to point out the "naive" answer to one-time initialization of static methods, is hardly more code than that implementation of Singleton -- and has an essential advantage.

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.
    }
}

The advantage of this approach, is that you get to call with the straightforward static function syntax:

MyClass::someMethod1();

Contrast it to the calls required by the accepted answer:

MyClass::getInstance->someMethod1();

As a general principle, it is best to pay the coding price once, when you code a class, to keep callers simpler.


Of all the answers (including this one), I prefer Victor Nicollet's answer. Simple. No extra coding required. No "advanced" coding to understand. (I recommend including FrancescoMM's comment, to make sure "init" will never execute twice.)

So I could have not bothered to write this answer. But so many people upvoted the accepted answer, that I conclude some people are simply not aware of the obvious, "naive", approach (that I show here). Understand this as a starting point.


There is a way to call the init() method once and forbid it's usage, you can turn the function into private initializer and ivoke it after class declaration like this:

class Example {
    private static function init() {
        // do whatever needed for class initialization
    }
}
(static function () {
    static::init();
})->bindTo(null, Example::class)();

If you don't like public static initializer, reflection can be a workaround.

<?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');

?>

Note - the RFC proposing this is still in the draft state.


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

proposed for PHP 7.x (see https://wiki.php.net/rfc/static_class_constructor )

참고URL : https://stackoverflow.com/questions/3312806/static-class-initializer-in-php

반응형