정적 메소드 사용에 대한 주요 두 가지 이유는 다음과 같습니다.
- 정적 메소드를 사용하는 코드는 테스트 하기 어렵다
- 정적 메소드를 사용하는 코드는 확장 하기 어렵다
다른 메소드 안에 정적 메소드 호출이 있으면 실제로 전역 변수를 가져 오는 것보다 나쁩니다. PHP에서 클래스는 전역 기호이므로 정적 메서드를 호출 할 때마다 전역 기호 (클래스 이름)를 사용합니다. 글로벌이 악한 경우입니다. Zend Framework의 일부 구성 요소에 이러한 종류의 접근 방식에 문제가있었습니다. 객체를 빌드하기 위해 정적 메소드 호출 (공장)을 사용하는 클래스가 있습니다. 맞춤형 객체를 반환하기 위해 해당 인스턴스에 다른 팩토리를 제공하는 것은 불가능했습니다. 이 문제에 대한 해결책은 프로그램 시작시 인스턴스 및 instace 메소드 만 사용하고 싱글 톤 등을 시행하는 것입니다.
Google의 애자일 코치로 일하는 Miško Hevery 는 흥미로운 이론을 가지고 있거나 객체를 사용하는 시간과 객체 생성 시간을 분리해야한다고 조언합니다. 따라서 프로그램의 수명주기는 두 가지로 나뉩니다. main()
응용 프로그램의 모든 객체 배선과 실제 작업을 수행하는 부품을 처리하는 첫 번째 부분 ( 방법이라고합시다).
따라서 대신 :
class HttpClient
{
public function request()
{
return HttpResponse::build();
}
}
우리는 오히려해야합니다 :
class HttpClient
{
private $httpResponseFactory;
public function __construct($httpResponseFactory)
{
$this->httpResponseFactory = $httpResponseFactory;
}
public function request()
{
return $this->httpResponseFactory->build();
}
}
그런 다음 인덱스 / 메인 페이지에서 수행합니다 (이것은 객체 배선 단계 또는 프로그램에서 사용할 인스턴스 그래프를 만드는 시간입니다).
$httpResponseFactory = new HttpResponseFactory;
$httpClient = new HttpClient($httpResponseFactory);
$httpResponse = $httpClient->request();
주요 아이디어는 클래스에서 종속성을 분리하는 것입니다. 이렇게하면 코드가 훨씬 확장 가능하고 나에게 가장 중요한 부분 인 테스트 가능합니다. 테스트 가능한 것이 왜 더 중요합니까? 항상 라이브러리 코드를 작성하지는 않기 때문에 확장 성이 그렇게 중요하지는 않지만 리팩토링을 수행 할 때 테스트 가능성이 중요합니다. 어쨌든 테스트 가능한 코드는 일반적으로 확장 가능한 코드를 생성하므로 실제로는 상황이 아닙니다.
Miško Hevery는 또한 싱글 톤과 싱글 톤 (자본 S의 유무에 관계없이)을 명확하게 구분합니다. 차이점은 매우 간단합니다. 소문자 "s"가있는 싱글 톤은 인덱스 / 메인의 배선으로 시행됩니다. Singleton 패턴을 구현 하지 않는 클래스의 객체를 인스턴스화하고 해당 인스턴스를 필요한 다른 인스턴스에만 전달하도록주의하십시오. 반면, 대문자 "S"를 가진 Singleton은 고전적인 (반) 패턴의 구현입니다. 기본적으로 PHP 세계에서 많이 사용하지 않는 위장의 세계. 나는 지금까지 하나를 보지 못했습니다. 모든 클래스에서 단일 DB 연결을 사용하려면 다음과 같이하는 것이 좋습니다.
$db = new DbConnection;
$users = new UserCollection($db);
$posts = new PostCollection($db);
$comments = new CommentsCollection($db);
위의 작업을 수행하면 싱글 톤이 있으며 테스트에 모의 또는 스터브를 주입하는 좋은 방법이 있습니다. 놀랍게도 단위 테스트가 더 나은 디자인으로 이어지는 방법입니다. 그러나 테스트를 통해 해당 코드를 사용하는 방식에 대해 생각해야한다고 생각할 때 많은 의미가 있습니다.
/**
* An example of a test using PHPUnit. The point is to see how easy it is to
* pass the UserCollection constructor an alternative implementation of
* DbCollection.
*/
class UserCollection extends PHPUnit_Framework_TestCase
{
public function testGetAllComments()
{
$mockedMethods = array('query');
$dbMock = $this->getMock('DbConnection', $mockedMethods);
$dbMock->expects($this->any())
->method('query')
->will($this->returnValue(array('John', 'George')));
$userCollection = new UserCollection($dbMock);
$allUsers = $userCollection->getAll();
$this->assertEquals(array('John', 'George'), $allUsers);
}
}
정적 멤버를 사용하고 PHP 5.3에서 JavaScript 프로토 타입 객체를 흉내 내기 위해 사용했던 유일한 상황은 각 필드가 동일한 값의 교차 인스턴스를 가질 것이라는 것을 알 때입니다. 이 시점에서 정적 속성과 정적 getter / setter 메서드 쌍을 사용할 수 있습니다. 어쨌든 정적 멤버를 인스턴스 멤버로 대체 할 가능성을 추가하는 것을 잊지 마십시오. 예를 들어 Zend Framework는의 인스턴스에 사용 된 DB 어댑터 클래스의 이름을 지정하기 위해 정적 속성을 사용하고 Zend_Db_Table
있었습니다. 더 이상 관련이 없을 수 있으므로 사용했던 지 오래되었습니다. 그러나 그것이 제가 기억하는 방식입니다.
정적 속성을 처리하지 않는 정적 메서드는 함수 여야합니다. PHP에는 함수가 있으므로 사용해야합니다.