programing

PHP 프로젝트에서 도우미 개체를 저장, 액세스 및 정리하기 위한 패턴은 무엇입니까?

nicescript 2023. 1. 13. 20:06
반응형

PHP 프로젝트에서 도우미 개체를 저장, 액세스 및 정리하기 위한 패턴은 무엇입니까?

PHP 기반의 객체 지향 프로젝트에서 데이터베이스 엔진, 사용자 알림, 오류 처리 등과 같은 도우미 객체를 어떻게 구성하고 관리합니까?

예를 들어 큰 PHP CMS를 가지고 있다고 합시다.CMS는 다양한 클래스로 구성되어 있습니다.몇 가지 예:

  • 데이터베이스 객체
  • 사용자 관리
  • 아이템을 작성/수정/삭제하기 위한 API
  • 최종 사용자에게 메시지를 표시하는 메시지 개체
  • 오른쪽 페이지로 이동하는 컨텍스트 핸들러
  • 버튼을 표시하는 내비게이션 바 클래스
  • 벌목 객체
  • 커스텀 에러 처리

기타.

저는 어떻게 하면 이러한 오브젝트를 필요로 하는 시스템의 각 부분에 가장 잘 접근할 수 있게 할 수 있을까라는 영원한 질문에 대처하고 있습니다.

몇 년 전 제 첫 번째 앱은 이러한 클래스의 초기화된 인스턴스를 포함하는 $application global이었습니다.

global $application;
$application->messageHandler->addMessage("Item successfully inserted");

그 후 싱글톤 패턴과 공장 기능으로 전환했습니다.

$mh =&factory("messageHandler");
$mh->addMessage("Item successfully inserted");

그것도 마음에 들지 않아요.유닛 테스트와 캡슐화는 나에게 점점 더 중요해지고, 글로벌/싱글톤의 논리를 이해하는 데 있어 OOP의 기본 개념을 파괴한다.

그리고 물론 각 오브젝트가 필요로 하는 도우미 오브젝트에 대한 포인터(아마도 가장 깨끗하고 자원 절약적이며 테스트하기 쉬운 방법)를 제공할 수 있지만, 장기적으로 이 오브젝트의 유지보수가 가능한지 의문입니다.

제가 조사한 대부분의 PHP 프레임워크는 싱글톤 패턴 또는 초기화된 오브젝트에 액세스하는 함수를 사용합니다.둘 다 좋은 방법이지만, 말했듯이 난 둘 다 만족하지 않아.

나는 여기에 존재하는 공통적인 패턴에 대해 시야를 넓히고 싶다.저는 장기적인 현실적 관점에서 이 문제를 논의할 수 있는 예, 추가 아이디어 및 리소스를 위한 포인터를 찾고 있습니다.

또한, 저는 이 문제에 대한 전문적이고 틈새 있는, 또는 명백한 이상한 접근법에 대해 듣고 싶습니다.

나는 플라비우스가 제안한 싱글톤 접근법을 피하겠다.이 접근방식을 회피하는 이유는 여러 가지가 있습니다.좋은 OOP 원칙을 위반합니다.구글 테스트 블로그에는 싱글톤에 관한 좋은 기사 및 회피 방법이 게재되어 있습니다.

http://googletesting.blogspot.com/2008/08/by-miko-hevery-so-you-join-new-project.html http://googletesting.blogspot.com/2008/05/tott-using-dependancy-injection-to.html http://googletesting.blogspot.com/2008/08/where-have-all-singletons-gone.html

대체 수단

  1. 서비스 제공자

    http://java.sun.com/blueprints/corej2eepatterns/Patterns/ServiceLocator.html

  2. 의존성 주입

    http://en.wikipedia.org/wiki/Dependency_injection

    및 php 설명:

    http://components.symfony-project.org/dependency-injection/trunk/book/01-Dependency-Injection

다음은 다음 대체 방법에 대한 좋은 기사입니다.

http://martinfowler.com/articles/injection.html

의존성 주입(DI) 구현:

플라비우스의 해결책에 대해 좀 더 생각해 봅시다.나는 이 게시물이 반 포스트가 되는 것을 원하지 않지만, 나는 의존성 주입이 적어도 나에게 지구본보다 나은 이유를 아는 것이 중요하다고 생각한다.

비록 이것이 '진정한' 싱글턴의 구현은 아니지만, 나는 여전히 플라비우스가 그것을 잘못 이해했다고 생각한다.글로벌 상태가 불량입니다.이러한 솔루션에서는 정적 방법을 테스트하는 데도 어려움이 있습니다.

많은 사람들이 그렇게 하고, 승인하고, 사용하는 것으로 알고 있습니다.하지만 Misko Heberies 블로그 기사(구글 테스트 가능성 전문가)를 읽고, 다시 읽고, 그가 말한 것을 천천히 소화하는 것은 디자인에 대한 나의 시각을 크게 바꿔놓았다.

애플리케이션을 테스트하려면 다른 접근방식을 채택하여 애플리케이션을 설계해야 합니다.테스트 첫 번째 프로그래밍을 실행하면 다음과 같은 문제가 발생합니다.다음으로 이 코드로 로깅을 구현합니다.기본 메시지를 기록하는 테스트를 먼저 작성합시다.그런 다음 대체할 수 없는 글로벌 로거를 작성 및 사용해야 하는 테스트를 작성합니다.

저는 그 블로그에서 얻은 모든 정보에 대해 여전히 어려움을 겪고 있으며, 구현이 항상 쉽지만은 않으며, 질문도 많습니다.하지만 Misko Hebery가 말한 내용을 파악한 후 이전 상태로 돌아갈 수 있는 방법은 없습니다(예, 글로벌 상태 및 싱글톤(빅 S) :-).

class Application {
    protected static $_singletonFoo=NULL;

    public static function foo() {
        if(NULL === self::$_singletonFoo) {
            self::$_singletonFoo = new Foo;
        }
        return self::$_singletonFoo;
    }

}

나는 이렇게 할 것이다.온 디맨드로 오브젝트를 만듭니다.

Application::foo()->bar();

내가 하는 방식이고 OOP 원칙을 존중하고 지금 하는 방식보다 코드 수가 적으며 코드가 처음 필요할 때만 오브젝트가 생성됩니다.

주의: 제가 제시한 것은 진짜 싱글톤 패턴도 아닙니다.싱글톤은 컨스트럭터(Foo::_constructor())를 프라이빗으로 정의함으로써 자신의 인스턴스를 1개만 허용합니다.모든 "응용 프로그램" 인스턴스에서 사용할 수 있는 "글로벌" 변수입니다.그것이 좋은 OOP 원칙을 무시하지 않기 때문에 나는 그것의 사용이 타당하다고 생각한다.물론, 세상의 모든 것들과 마찬가지로, 이 "패턴"도 너무 많이 사용되어서는 안 된다!

저는 이것이 많은 PHP 프레임워크, 그 중에서도 Zend Framework와 Yii에서 사용되는 것을 봐왔습니다.그리고 틀을 사용해야 합니다.어떤 거인지는 안 알려줄 거예요.

부록 여러분 중 TDD에 대해 우려하는 분들을 위해, 종속성을 주입하기 위해 몇 가지 배선을 구성할 수 있습니다.다음과 같은 경우가 있습니다.

class Application {
        protected static $_singletonFoo=NULL;
        protected static $_helperName = 'Foo';

        public static function setDefaultHelperName($helperName='Foo') {
                if(is_string($helperName)) {
                        self::$_helperName = $helperName;
                }
                elseif(is_object($helperName)) {
                        self::$_singletonFoo = $helperName;
                }
                else {
                        return FALSE;
                }
                return TRUE;
        }
        public static function foo() {
                if(NULL === self::$_singletonFoo) {
                        self::$_singletonFoo = new self::$_helperName;
                }
                return self::$_singletonFoo;
        }
}

개선의 여지가 충분히 있다.그냥 PoC일 뿐이야, 상상력을 발휘해봐.

왜 그럴까?대부분의 경우 어플리케이션은 유닛 테스트가 되지 않고 실제 가동 환경에서 실행됩니다.PHP의 장점은 속도입니다.PHP는 Java와 같은 "깨끗한 OOP 언어"가 아니며 앞으로도 아닐 것입니다.

어플리케이션 내에는 어플리케이션클래스는 1개뿐이고 도우미의 인스턴스는 1개뿐입니다(위에서 설명한 바와 같이 느린 로딩에 따라).물론 싱글톤은 나쁘지만 현실세계에 충실하지 않을 때만 그렇다.제 예에서는 그렇습니다.

"싱글톤은 나쁘다"와 같은 틀에 박힌 "규칙"은 악의 근원으로, 스스로 생각하려 하지 않는 게으른 사람들을 위한 것이다.

그래, 나도 알아, 엄밀히 말하면 PHP 선언이 나쁘다는 걸.하지만 이 언어는 그 진부한 방식으로 성공한 언어이다.

부록

하나의 기능 스타일:

function app($class) {
    static $refs = array();

    //> Dependency injection in case of unit test
    if (is_object($class)) {
        $refs[get_class($class)] = $class;
        $class = get_class($class);
    }

    if (!isset($refs[$class]))
        $refs[$class] = new $class();

    return $refs[$class];
}

//> usage: app('Logger')->doWhatever();

Dependency Injection(의존성 주입) 개념을 좋아합니다.

"의존성 주입은 구성 요소가 생성자, 메서드를 통해 또는 직접 필드에 종속성을 부여하는 것입니다.(Pico Container 웹사이트에서)"

Fabien Potensier는 Dependency Injection과 그 사용의 필요성에 관한 훌륭한 일련의 기사를 썼습니다.그는 또한 Pimple이라는 이름의 작고 좋은 Dependency Injection Container도 제공하고 있습니다(github에 대한 자세한 정보).

위와 같이 싱글톤을 사용하는 것을 좋아하지 않습니다.싱글톤이 왜 좋은 디자인이 아닌지에 대한 좋은 요약은 여기 Steve Yegge의 블로그에서 찾을 수 있습니다.

가장 좋은 방법은 이러한 리소스를 위한 일종의 컨테이너를 갖는 것입니다. 컨테이너를 실장하는 가장 일반적인 방법에는 다음과 같은 것이 있습니다.

싱글턴

테스트하기 어렵고 글로벌 상태를 의미하기 때문에 권장되지 않습니다.(단막염)

레지스트리

싱글톤을 제거해 줍니다.레지스트리도 추천하지 않습니다.싱글톤의 일종이기 때문입니다.(유닛 테스트의 어려움)

상속

아쉽게도 PHP에는 여러 상속이 없기 때문에 체인으로 제한됩니다.

의존성 주입

이것이 더 나은 접근법이지만 더 큰 토픽입니다.

전통적인.

이를 위한 가장 간단한 방법은 생성자 또는 세터 주입(세터 또는 클래스 생성자를 사용하는 종속성 개체 통과)을 사용하는 것입니다.

프레임워크

자체 종속성 주입기를 롤링하거나 종속성 주입 프레임워크 중 일부를 사용할 수 있습니다.야디프

응용 프로그램 리소스

컨테이너 역할을 하는 애플리케이션 부트스트랩의 각 리소스를 초기화하고 부트스트랩 개체에 액세스하는 앱의 모든 위치에서 액세스할 수 있습니다.

이것은 Zend Framework 1.x에서 구현된 접근법입니다.

자원 로더

필요한 경우에만 필요한 리소스를 로드(생성)하는 일종의 정적 개체입니다.이것은 매우 현명한 접근법입니다.Symfony의 종속성 주입 구성 요소 구현과 같은 실제 작업을 볼 수 있습니다.

특정 레이어에 대한 주입

응용 프로그램의 어디에나 리소스가 반드시 필요한 것은 아닙니다.경우에 따라서는 컨트롤러(MV C )에 필요한 경우가 있습니다.그런 다음 해당 위치에만 리소스를 주입할 수 있습니다.

일반적인 방법은 docblock 주석을 사용하여 주입 메타데이터를 추가하는 것입니다.

이 문제에 대한 저의 접근방식을 보시기 바랍니다.

Zend Framework에서 종속성 주입을 사용하는 방법 - 스택 오버플로

마지막으로 캐싱이라는 매우 중요한 사항에 대해 설명하겠습니다.
일반적으로 선택한 기술에 관계없이 리소스가 어떻게 캐시될지 생각해야 합니다.캐시는 리소스 자체입니다.

응용 프로그램은 매우 커질 수 있으며, 각 요청에 따라 모든 리소스를 로드하는 것은 매우 비용이 많이 듭니다.appserver-in-php - Google 코드에서의 프로젝트 호스팅을 포함한 많은 접근 방식이 있습니다.

오브젝트를 글로벌하게 사용할 수 있도록 하려면 레지스트리 패턴에 관심이 있을 수 있습니다.자세한 내용은 Zend Registry를 참조하십시오.

레지스트리와 싱글톤 질문입니다.

PHP의 오브젝트는 유닛 테스트에서 알 수 있듯이 메모리를 많이 사용합니다.따라서 불필요한 오브젝트를 가능한 한 빨리 파기하여 다른 프로세스의 메모리를 절약하는 것이 이상적입니다.모든 물체는 두 개의 금형 중 하나에 들어맞는다는 것을 알게 되었습니다.

1) 오브젝트에 유용한 메서드가 많이 있거나 여러 번 호출해야 할 수 있습니다.이 경우 싱글톤/레지스트리를 구현합니다.

$object = load::singleton('classname');
//or
$object = classname::instance(); // which sets self::$instance = $this

2) 오브젝트는 오브젝트를 호출하는 메서드/함수의 수명 동안만 존재하며, 이 경우 오브젝트 참조가 오래 지속되는 것을 방지하기 위해 단순한 작성에 도움이 됩니다.

$object = new Class();

임시 개체를 어디에 저장하면 스크립트의 나머지 시간 동안 개체를 메모리에 보관하는 것을 잊어버릴 수 있으므로 메모리 누수가 발생할 수 있습니다.

초기화 개체를 반환하는 함수를 선택합니다.

A('Users')->getCurrentUser();

테스트 환경에서는 목업을 반환하도록 정의할 수 있습니다.debug_backtrace()를 사용하여 함수를 호출하고 다른 개체를 반환하는 내부 사용자도 검출할 수 있습니다.프로그램 내에서 실제로 무슨 일이 일어나고 있는지 알기 위해 어떤 오브젝트를 얻고 싶은지 등록하면 됩니다.

훌륭한 매뉴얼을 읽어보는 건 어떨까요?

http://php.net/manual/en/language.oop5.autoload.php

언급URL : https://stackoverflow.com/questions/1812472/in-a-php-project-what-patterns-exist-to-store-access-and-organize-helper-objec

반응형