2014-05-10 2 views
3

PHP 프로젝트를 해킹으로 변환하는 중입니다. 그리고 저는 약간의 도로 블록을 발견했습니다. 내가하려는 일은 PHP에서 Hack으로 IoC 컨테이너를 다시 작성하는 것이며 해킹 유형 검사기 도구를 통과하는 데 모든 문제가 발생합니다.해킹에 IoC 컨테이너 작성하기

그래서 기본적으로 매핑 문자열을 등록 할 수있는 컨테이너가 있습니다. 아이디어는 클로저가 클래스를 인스턴스화하는 로직을 포함한다는 것입니다. 컨테이너는 또한 생성 한 인스턴스를 저장하고 강제로 새 인스턴스를 만들도록 허용합니다. Container::get() 또는 Container::getNew()를 사용하는 경우 때

<?hh // strict 
class Container { 
    private Map<string, mixed> $instances = Map {}; 
    private Map<string, (function (Container): mixed)> $registered = Map {}; 

    public function register(string $alias, (function (Container): mixed) $closure): void 
    {  
     $this->registered[$alias] = $closure; 
    } 

    public function get(string $alias): ?mixed 
    { 
     if (!$this->registered->contains($alias)) { 
      return null; 
     } 

     $instance = $this->instances->get($alias); 
     if ($instance !== null) { 
      return $instance; 
     } 

     $closure = $this->registered->get($alias); 
     if ($closure !== null) { 
      $this->instances->set($alias, $closure($this)); 
     } 
     return $this->instances->get($alias); 
    } 

    public function getNew(string $alias): ?mixed 
    { 
     if (!$this->registered->contains($alias)) { 
      return null; 
     } 

     $closure = $this->registered->get($alias); 
     return ($closure !== null) ? $closure($this) : null; 
    } 
} 

이 클래스 자체는 반환 유형 mixed이기 때문에 나는이 방법을 실행하려고 할 때, 그것은이 오류가 발생, 유형 검사를 통과 보이지만 : 여기 내 컨테이너 코드 이들에 의해 반환 된 객체에 :

당신은 멤버 X에 액세스하려고하지만,이 객체가 아닌, 그것은

지금 나는이 의미가 알고있는 혼합 값을하고, 수 원인은 분명히 비 객체를 허용하므로, is_object()에 이러한 코드를 래핑해야합니다. 그러나 이렇게하면 형식 검사기에서 오류를 표시하지 않는 것처럼 보입니다. 해킹에서 객체가 무엇인지 확인하는 더 좋은 방법이 있습니까? 유형 검사기가이를 이해합니다.

또한이 IoC 컨테이너 클래스는 혼합 유형에 크게 의존합니다. 이는 저에게 다소 추한 것입니다. 런타임시 반환 값이 객체인지 확인하는 것은 이상적이지 않습니다. 내가 할 수있는 더 좋은 방법이 있니? IContainable 또는 뭔가 같은 인터페이스 변경 혼합 생각을 가지고 노는 시도하고 컨테이너에 저장하려는 모든 클래스가 있지만이 형식 검사기 IContainable 인터페이스 메서드를 포함하지 않았다는 불평했다. 컨테이너에서 반환 된 객체를 호출하려고했는데 (코드의 같은 지점에서 오류가 발생했지만 다른 이유가 있음). 아마도 나는이 접근법으로 성공에 가깝습니까?

도움 주셔서 감사합니다.

답변

11

유형 검사기가 이해할 수있는 해킹 개체가 있는지 확인하는 더 좋은 방법이 있습니까?

아마도 instanceof을 통해 특정 인스턴스를 확인하고 싶을 것입니다. 예를 들어 :

<?hh // strict 

class C { 
    public function f(): void {} 
} 

function f(): mixed { 
    return new C(); 
} 

function g(): void { 
    $c = f(); 
    // $c->f() won't work out here, $c is mixed 
    if ($c instanceof C) { 
    $c->f(); // This works now 
    } 
} 

은 또한 당신이 ?mixed을하지 않으려는주의 (경고, 코드는 브라우저에 직접 입력), 그 중복입니다 - 단지 mixed를 사용합니다. (혼합 아무것도 할 수 있기 때문에, 그것은 또한 널 (null)이 될 수 있습니다. 오류를 생성하면 ?mixed 어떤 시점에서 할 일이 내 목록에 쓸 때. :)) 또한

는이 IoC 컨테이너 클래스에 크게 의존 나는 약간 추한 혼합 유형입니다.

여기 직감이 좋습니다. Facebook에서 우리는 mixed과 같은 형식을 입력하려는 경우 대부분 1) 더 구체적인 유형이 있어야하며 2) 코드가 매우 저조한 구조를 취해야한다고 생각합니다. 더 나은 형식으로 구조화하십시오.

좀 더 구체적인 유형을 사용해야 할 수도 있습니다. 인터페이스를 사용하면 도움이됩니다. 위에 설명 된 instanceof 기능을 사용하여 수행 할 작업의 대부분이 실제로 해당 인터페이스의 일부인 것으로 밝혀지면 다른 작업을해야 할 때가 있습니다. Container을 정확히 사용하는 방법에 따라 using generics을 살펴볼 수도 있습니다. Container이 서로 다른 특정 서브 클래스 또는 인터페이스에 대해 여러 번 인스턴스화되는 경우 generics는 아마도 사용자가 원하는 것일 수 있습니다. 그것이 싱글 톤이라면 아마 그렇지 않을 수도 있습니다. 또한 여기에 표시하지 않더라도 어떤 식 으로든 보유하고있는 클래스와 Container이 상호 작용하는 경우 constraint on the generic이 필요할 수 있습니다.

하지만 구조상의 문제로 인해이 문제에 직면 해있는 것으로 보입니다. . 여기에 대해 생각해 보면 다음과 같은 것들이 있습니다. 왜 클래스에서 클래스를 인스턴스화하는 주변에 추상화 레이어가 필요한지 - 기능이 제공하는 기능과 해당 기능을 동질성있게 만들 수 있습니까 (즉, 입력 가능) 그리고 이기종 클래스 인스턴스화 문제로부터 분리 할 수 ​​있습니까? 형식 유형을 잠시 무시하면 (즉, 바닐라 PHP에서이 형식을 작성한 경우) Container 클래스는 올바른 결과를 얻고 있다는 것을 어떻게 알 수 있습니까? 무슨 일이 일어나고 있는지에 대한 지식이 있어야합니다. 그러나 비공식적으로 또는 다른 방법으로 호출 코드에 묶여 있어야합니다. 그렇지 않으면 이것이 처음부터 작동하지 않을 것입니다! 해당 정보가 어디서 어떻게 어떻게 목록 화되었는지 생각한 다음, 그 정보를 명확히 할 수있는 방법을 찾아 낼 수 있는지 확인하십시오.

희망이 도움이됩니다. 내가 무엇인가를 명확히 할 수 있다면 의견으로 알려주세요. 그리고 물론, 계속 묻고, FB 해킹 엔지니어 많은 지식 커뮤니티 회원은 밀접하게 :) "hacklang"태그를보고 :) (우리는 정말 흥분 해킹 BTW 해킹하고있다! 희망은 당신이있어)

+0

+1 멋진 대답에 내 솔루션을 볼 수 있습니다! 그리고 여기에 "hacklang"과 "hhvm"태그를 모니터링 해 주셔서 감사합니다. :). –

+0

굉장한 답변! 제네릭을 보았지만 컨테이너가 현재 싱글 톤으로 작동하므로 작동하지 않습니다. DI로 코딩하고 클래스와 그 의존성이 어떻게 인스턴스화되는지에 대한 로직을 래핑하는 것이 이치에 맞는 것처럼 보이기 때문에이 레이어를 추가했습니다. PHP에서 어떻게 작동했는지에 관해서는 기술적으로 PHP 코드가 올바른 것을 알지 못했다고 생각합니다. 프로그래머가 별칭이 어떤 클래스 인스턴스화에 할당되었는지를 아는 것만으로도 문제가 발생했습니다. 실행 시간에 잡힐 것입니다. 그래서 여기에 전환 만이 아니라, 다시 생각해보십시오. – ndavison

0

저는 6 개월 늦었지만이 문제에 대한 해결책을 제시하고자합니다.

저는이 문제를 해결하기 위해 프로젝트를 공장에서 검사하고 단일 클래스로 컴파일하는 스크립트를 작성했습니다.

user defined propertyprovides을 검색하면이 팩터 리의 별칭과 팩토리가 생성하는 개체 유형의 전체 이름이라는 두 가지 인수가 필요합니다. 또한 컴파일 스크립트는 각 팩토리가 컴파일 된 팩토리 클래스 인 단일 매개 변수 만 사용하는지 확인합니다.

기본적으로 런타임에 컨테이너를 채우는 대신 컴파일 할 때 채 웁니다. 컨테이너 클래스 정의는 컨테이너 인 컨테이너 클래스의 인스턴스가 아니라 컨테이너입니다.

그것은 여전히 ​​진행중인 작품,하지만 당신은 github