PHP 프로젝트에서 도우미 객체를 저장하고 액세스하고 구성하는 패턴은 무엇입니까? [닫은]
PHPPHP 프로젝트에서 도우미 객체를 저장하고 액세스하고 구성하는 패턴은 무엇입니까? [닫은]
PHP 기반의 객체 지향 프로젝트에서 데이터베이스 엔진, 사용자 알림, 오류 처리 등과 같은 도우미 객체를 어떻게 구성하고 관리합니까?
대형 PHP CMS가 있다고 가정 해보십시오. CMS는 다양한 클래스로 구성되어 있습니다. 몇 가지 예 :
기타
나는 영원한 질문을 다루고있다.이 객체를 필요로하는 시스템의 각 부분에 어떻게 접근 가능하게하는 것이 가장 좋은가?
내 첫 번째 접근 방식은 수년 전에이 클래스의 초기화 된 인스턴스가 포함 된 $ 응용 프로그램 전역을 사용하는 것이 었습니다.
global $application;
$application->messageHandler->addMessage("Item successfully inserted");
그런 다음 Singleton 패턴과 팩토리 함수로 변경했습니다.
$mh =&factory("messageHandler");
$mh->addMessage("Item successfully inserted");
그러나 나는 그것에 만족하지 않다. 유닛 테스트와 캡슐화는 점점 더 중요 해지고 있으며, 이해에서 전역 / 싱글 톤의 논리는 OOP의 기본 아이디어를 파괴합니다.
그렇다면 각 개체에 필요한 헬퍼 개체에 대한 많은 포인터를 제공 할 가능성이 있습니다. 아마도 가장 깨끗하고 자원을 절약하며 테스트 친화적 인 방법 일 수 있지만 장기적으로 유지 관리 가능성에 의문을 제기합니다.
대부분의 PHP 프레임 워크는 싱글 톤 패턴 또는 초기화 된 객체에 액세스하는 함수 중 하나를 사용합니다. 두 가지 모두 괜찮 았지만, 내가 말했듯이 나는 행복하지 않다.
나는 공통 패턴이 존재하는 것에 대한 나의 지평을 넓히고 싶다. 나는 장기적이고 실제적인 관점에서 이것을 토론하는 자원에 대한 예제, 추가 아이디어 및 조언을 찾고있다.
또한이 문제에 대한 전문화 된, 틈새 또는 평범한 이상한 접근법에 대해 듣고 싶습니다.
해결법
-
==============================
1.나는 Flavius가 제안한 Singleton 접근법을 피할 것이다. 이 접근법을 피하는 데는 여러 가지 이유가 있습니다. 그것은 좋은 OOP 원리를 위반한다. Google 테스트 블로그에는 Singleton에 대한 좋은 기사와 그것을 피하는 방법이 나와 있습니다.
나는 Flavius가 제안한 Singleton 접근법을 피할 것이다. 이 접근법을 피하는 데는 여러 가지 이유가 있습니다. 그것은 좋은 OOP 원리를 위반한다. Google 테스트 블로그에는 Singleton에 대한 좋은 기사와 그것을 피하는 방법이 나와 있습니다.
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
이 대안에 대한 좋은 기사입니다.
http://martinfowler.com/articles/injection.html
플라 비우스의 해결책에 대한 좀 더 많은 생각. 나는이 지위가 반 - 지위가되기를 원하지 않지만 적어도 내가 왜 의존성 주사가 세계에 비해 더 나은지를 아는 것이 중요하다고 생각합니다.
'진정한'Singleton 구현은 아니지만 Flavius가 잘못 생각한 것 같습니다. 전 지구적인 상태가 좋지 않습니다. 이러한 솔루션은 정적 메서드를 테스트하기도 어렵습니다.
나는 많은 사람들이 그것을하고 그것을 승인하고 사용한다는 것을 안다. 그러나 Misko Heverys의 블로그 기사 (Google 테스트 능력 전문가)를 읽은 다음 다시 읽은 다음 그가 말하는 것을 천천히 소화하여 디자인을 많이 변경했습니다.
응용 프로그램을 테스트 할 수있게하려면 응용 프로그램을 설계 할 때 다른 접근 방식을 채택해야합니다. 테스트 우선 프로그래밍을하면 다음과 같은 문제가 발생합니다. '다음에는이 코드 조각에 로깅을 구현하고 싶습니다. 먼저 기본 메시지를 기록한 테스트를 작성한 다음 교체 할 수없는 글로벌 로거를 작성하고 사용하도록하는 테스트를 시작하십시오.
나는 아직도 그 블로그에서 얻은 모든 정보로 어려움을 겪고 있으며 구현하기가 항상 쉬운 것은 아니며 많은 질문이 있습니다. 그러나 Misko Hevery가 말한 것을 파악한 후에 내가 전에 한 일 (예, 글로벌 상태와 Singletons (big S))으로 돌아갈 수있는 방법은 없습니다 :-)
-
==============================
2.
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 ())를 private으로 정의함으로써 오직 하나의 인스턴스 만 허용합니다. 모든 "응용 프로그램"인스턴스에서 사용할 수있는 "전역 변수"일뿐입니다. 그것이 좋은 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 언어"가 아니며 절대로 사용되지 않습니다.
응용 프로그램에는 Application 클래스가 하나 뿐이고 각 헬퍼 인스턴스가 하나만 있습니다 (위와 같은 지연로드에 따라 다름). 물론, 싱글 톤은 나쁘지 만, 다시 말해서 실제 세계를 고수하지 않는 경우에만 그렇습니다. 나의보기에서는, 그들은.
"싱글 톤은 나쁘다"와 같은 고정 된 "규칙"은 악의 근원이며 게으른 사람들을 위해 스스로 생각하고 싶어하지 않습니다.
그래, 나도 알아, PHP 선언문은 기술적으로 말하면 나쁜 것이다. 그러나 그것은 hackish 방식으로 성공적인 언어입니다.
하나의 함수 스타일 :
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();
-
==============================
3.나는 Dependency Injection의 개념을 좋아한다 :
나는 Dependency Injection의 개념을 좋아한다 :
Fabien Potencier는 Dependency Injection과 그것들을 사용할 필요성에 대한 기사를 정말 훌륭하게 썼습니다. 그는 또한 Pimple이라는 훌륭하고 작은 Dependency Injection Container를 제공합니다. Pimple은 정말 많이 사용하고 싶습니다 (github에 관한 더 많은 정보).
위에서 언급했듯이, 나는 싱글 톤의 사용을 좋아하지 않는다. 싱글 톤이 좋은 디자인이 아닌 이유에 대한 좋은 요약은 Steve Yegge의 블로그에서 찾을 수 있습니다.
-
==============================
4.가장 좋은 방법은 이러한 자원을위한 일종의 컨테이너를 갖는 것입니다. 이 컨테이너를 구현하는 가장 일반적인 방법은 다음과 같습니다.
가장 좋은 방법은 이러한 자원을위한 일종의 컨테이너를 갖는 것입니다. 이 컨테이너를 구현하는 가장 일반적인 방법은 다음과 같습니다.
테스트하기 어려우므로 전역 상태를 암시하므로 권장되지 않습니다. (단일 염염)
싱글 톤 (singletonitis)을 없애 버리고, 레지스트리도 추천하지 않습니다. 싱글 톤이기도합니다. (단단한 단위 테스트)
불행히도, PHP에는 다중 상속이 없기 때문에 모든 것을 체인에 제한합니다.
이것은 더 나은 접근 방식이지만 더 큰 주제입니다.
이를 수행하는 가장 간단한 방법은 생성자 또는 setter 주입 (setter 또는 클래스 생성자를 사용하여 종속성 객체 전달)을 사용하는 것입니다.
자신의 의존성 인젝터를 롤하거나 의존성 주입 프레임 워크 중 일부를 사용하여 (예 : 야디프
응용 프로그램 부트 스트랩 (컨테이너 역할을 함)에서 각 리소스를 초기화하고 부트 스트랩 객체에 액세스하는 응용 프로그램의 모든 위치에 리소스에 액세스 할 수 있습니다.
이것은 Zend Framework 1.x에서 구현 된 접근 방식입니다.
필요할 때만 필요한 리소스를로드 (생성)하는 정적 객체의 일종입니다. 이것은 매우 똑똑한 접근법입니다. 예를 들어 실제로보실 수 있습니다. Symfony의 Dependency Injection 컴포넌트 구현하기
리소스가 애플리케이션의 어느 곳에서나 항상 필요하지는 않습니다. 때로는 그들을 필요로하는 경우도 있습니다. 컨트롤러 (MV C)에서. 그런 다음 그곳에 만 리소스를 주입 할 수 있습니다.
이에 대한 일반적인 접근 방법은 docblock 주석을 사용하여 주입 메타 데이터를 추가하는 것입니다.
이에 대한 나의 접근법을 보라.
Zend Framework에서 의존성 주입을 사용하는 방법? - 스택 오버플로
결국 여기에 매우 중요한 캐싱에 대한 메모를 추가하고 싶습니다. 일반적으로 선택하는 기술에도 불구하고 리소스가 캐시되는 방식을 고려해야합니다. 캐시는 자원 자체가됩니다.
응용 프로그램은 매우 클 수 있으며 각 요청시 모든 자원을로드하는 것은 매우 비쌉니다. 이 appserver-in-php를 포함한 많은 접근법이 있습니다 - Google Code의 Project Hosting.
-
==============================
5.객체를 전역 적으로 사용할 수있게하려면 레지스트리 패턴이 재미있을 수 있습니다. 영감을 얻으려면 Zend Registry를 살펴보십시오.
객체를 전역 적으로 사용할 수있게하려면 레지스트리 패턴이 재미있을 수 있습니다. 영감을 얻으려면 Zend Registry를 살펴보십시오.
또한 레지스트리 대 싱글 톤 질문.
-
==============================
6.PHP의 객체는 단위 테스트에서 보았 듯이 상당한 양의 메모리를 차지합니다. 따라서 다른 프로세스를 위해 메모리를 절약하기 위해 가능한 빨리 불필요한 객체를 파괴하는 것이 이상적입니다. 그 점을 염두에두고 나는 모든 물체가 두 개의 곰팡이 중 하나에 들어 맞는다는 것을 발견했습니다.
PHP의 객체는 단위 테스트에서 보았 듯이 상당한 양의 메모리를 차지합니다. 따라서 다른 프로세스를 위해 메모리를 절약하기 위해 가능한 빨리 불필요한 객체를 파괴하는 것이 이상적입니다. 그 점을 염두에두고 나는 모든 물체가 두 개의 곰팡이 중 하나에 들어 맞는다는 것을 발견했습니다.
1) 객체는 여러 유용한 메소드를 가지고 있거나 싱글 톤 / 레지스트리를 구현하는 경우 두 번 이상 호출해야합니다.
$object = load::singleton('classname'); //or $object = classname::instance(); // which sets self::$instance = $this
2) 객체는 메서드 / 함수를 호출 할 때만 존재합니다.이 경우 간단한 생성은 객체 참조가 느리게 객체를 유지하는 것을 방지하는 데 유용합니다.
$object = new Class();
임시 객체를 저장하면 메모리 누수가 발생할 수 있습니다. 그 이유는 객체에 대한 참조가 나머지 스크립트에 대해 메모리에 객체를 보관하는 것을 잊어 버릴 수 있기 때문입니다.
-
==============================
7.초기화 된 객체를 반환하는 함수로 이동합니다.
초기화 된 객체를 반환하는 함수로 이동합니다.
A('Users')->getCurrentUser();
테스트 환경에서는 모형을 반환하도록 정의 할 수 있습니다. debug_backtrace ()를 사용하여 누가 함수를 호출했는지 탐지 할 수 있으며 다른 객체를 반환 할 수 있습니다. 어떤 객체를 얻고 자 하는지를 내부에 등록하여 프로그램 내부에서 실제로 무엇이 진행되고 있는지 통찰력을 얻을 수 있습니다.
-
==============================
8.좋은 설명서를 읽지 않는 이유는 무엇입니까?
좋은 설명서를 읽지 않는 이유는 무엇입니까?
http://php.net/manual/en/language.oop5.autoload.php
from https://stackoverflow.com/questions/1812472/in-a-php-project-what-patterns-exist-to-store-access-and-organize-helper-objec by cc-by-sa and MIT license
'PHP' 카테고리의 다른 글
cURL 오류 60 : SSL 인증서 : 로컬 발급자 인증서를 가져올 수 없습니다. (0) | 2018.09.13 |
---|---|
OpenCart 전문가가되는 방법? (0) | 2018.09.13 |
값에 의한 PHP 배열 삭제 (키가 아님) (0) | 2018.09.13 |
Magento에서 간단한 'Hello World'모듈을 만드는 방법은 무엇입니까? (0) | 2018.09.13 |
Mcrypt에서 OpenSSL으로 암호화 라이브러리 업그레이드 (0) | 2018.09.13 |