2013-03-13 4 views
1

함수의 정의를 위임하기 위해 인터페이스를 사용할 수 있지만 함수 호출을 허용 할 수있는 것을 찾을 수 없다는 것을 이해합니다. 함수를 사용하여 다른 클래스의 멤버 인 클래스를 만드는 경우 (해당 클래스를 통해 필수 함수가 해당 함수의 일부로 호출되도록 자동으로 보장). 내 말은PHP 필수 함수 호출

, 더 명확하게 :

class domain { 

    function isEmpty($input) { 
     //apply conditional logic and results 
    } 
} 
class test extends domain { 

    function addTestToDBTable($test) { 
     /** 
     * try to add but this class automatically makes it so that all rules of 
     * class domain must be passed before it can run 
     * - so essentially, I am no longer required to call those tests for each and 
     * every method 
     **/ 
    } 
} 

사과를이 어떤 방법으로 조리 나타납니다합니다. 물론, 그것은 게으른 것 같다하지만 난 이란게 우려하지 않고 문맥을 강제 할 수 있도록하려는

업데이트 : 확장 할 경우, PHP와 아이를위한 __construct()를 선언

좋아이 더 명확히하기 해당 하위 클래스는 부모 __construct()를 재정의합니다. 나는 이것을 원하지 않는다. 나는 부모 구조가 남아 있고, 어린이 교실이 그렇게 할 수있는 것처럼 기쁘게하는 것을 요구한다.

+0

당신이 인터페이스 또는 추상 클래스를 의미합니까? –

+0

아마'addTestToDBTable' (또는 다른 함수 이름)을'domain' 안에 만들 수 있고'parent :: addTestToDBTable()'을 할 수 있습니다. –

+0

예를 들어, 규칙이 적용되지 않은 경우, 자동으로 오류를 출력하고 싶습니다. 규칙을 모든 개별 기능에 적용하지 않고 규칙을 적용해야합니다. 해당 수퍼 클래스가 자동으로 해당 규칙 (예 : 기본 또는 맞춤 설정)을 적용하기를 바랍니다. – user784446

답변

0

나는 그것이 두 가지 다른 방법으로 수행 될 수 있다고 생각한다. 이 도움이

<?php 
class A { 
    public function callMe() { 
     echo __METHOD__ . "\n"; 
    } 
} 

class B extends A { 

    // prevents instantiation 
    public function __construct() { 
    } 

    public function shouldCallMe() { 
     echo __METHOD__ . "\n"; 
    } 

    public static function newInstance() { 
     return new ABProxy(); 
    } 
} 

class ABProxy { 
    private $b; 

    public function __construct() { 
     $this->b = new B(); 
    } 

    public function __call($method, $args) { 
     $this->b->callMe(); 
     return call_user_func_array(array($this->b, $method), $args); 
    } 
} 

// make the call 
$b = B::newInstance(); 
$b->shouldCallMe(); 

// Outputs 
// ------------------ 
// A::callMe 
// B::shouldCallMe 

희망 :

Aspect 지향적 인 프로그래밍

정말 간단한 예제가 될 수있다 여기 https://github.com/AOP-PHP/AOP

생성 또는 쓰기 프록시 클래스

A A 보라 약간.

0

원하는 소리가 Decorator입니다.

자세한 방법은 This answer을 참조하십시오. 에 클래스 확장이 필요하지 않습니다.

0

일부 문서 블록 메타 프로그래밍과 함께 도메인 유효성 검사 데코레이터를 사용합니다. 그러나 이것은 정말로 의심의 여지가없는 전체 도서관을위한 일입니다.

fiddle

<?php 
class FooDomain { 
    public static function is_not_empty($input) { 
     return !empty($input); 
    } 
} 

class Foo { 
    /** 
    * @domain FooDomain::is_not_empty my_string 
    */ 
    public function print_string($my_string) { 
     echo $my_string . PHP_EOL; 
    } 
} 

$foo = new DomainValidator(new Foo()); 
$foo->print_string('Hello, world!'); 
try { 
    $foo->print_string(''); // throws a DomainException 
} catch (\DomainException $e) { 
    echo 'Could not print an empty string...' . PHP_EOL; 
} 

// --- 

class DomainValidator { 
    const DOMAIN_TAG = '@domain'; 

    private $object; 

    public function __construct($object) { 
     $this->object = $object; 
    } 

    public function __call($function, $arguments) { 
     if (!$this->verify_domain($function, $arguments)) { 
      throw new \DomainException('Bad domain!'); 
     } 

     return call_user_func_array(
      array($this->object, $function), 
      $arguments 
     ); 
    } 

    public function __get($name) { 
     return $this->object->name; 
    } 

    public function __set($name, $value) { 
     $this->object->name = $value; 
    } 

    private function verify_domain($function, $arguments) { 
     // Get reference to method 
     $method = new \ReflectionMethod($this->object, $function); 
     $domains = $this->get_domains($method->getDocComment()); 
     $arguments = $this->parse_arguments(
      $method->getParameters(), 
      $arguments 
     ); 
     foreach ($domains as $domain) { 
      if (!call_user_func(
       $domain['name'], 
       $arguments[$domain['parameter']] 
      )) { 
       return false; 
      } 
     } 
     return true; 
    } 

    private function get_domains($doc_block) { 
     $lines = explode("\n", $doc_block); 
     $domains = array(); 
     $domain_tag = DomainValidator::DOMAIN_TAG . ' '; 
     foreach ($lines as $line) { 
      $has_domain = stristr($line, $domain_tag) !== false; 
      if ($has_domain) { 
       $domain_info = explode($domain_tag, $line); 
       $domain_info = explode(' ', $domain_info[1]); 
       $domains[] = array(
        'name'  => $domain_info[0], 
        'parameter' => $domain_info[1], 
       ); 
      } 
     } 
     return $domains; 
    } 

    private function parse_arguments($parameters, $values) { 
     $ret = array(); 
     for ($i = 0, $size = sizeof($values); $i < $size; $i++) { 
      $ret[$parameters[$i]->name] = $values[$i]; 
     } 
     return $ret; 
    } 
} 

출력 :

Hello, world! 
Could not print an empty string... 
+0

죄송합니다. 더 자세히 읽어 보겠습니다. 그러나, 나는 그것에 대해 좀 더 본질적으로 생각해 보았습니다. 부모 클래스는 자식 클래스의 메서드를 "알 수 있어야"하거나 자식 클래스가 자신의 메서드를 "알"수 있어야합니다 (즉, 메소드를 등록하기위한 생성자). 나는 그걸하는 법을 정말로 모른다. – user784446

+0

@ user784446 PHP에는 리플렉션이 있지만 느리기 때문에 프로덕션 중에 사용하지 않을 것입니다. [\ ReflectionClass'] (http://www.php.net/manual/en/class.reflectionclass.php)를 호출하고 [getMethods' 메소드] (http : //www.php.net/manual/en/reflectionclass.getmethods.php). 진짜 문제는 모든 메소드 호출을 가로 챌 수 없다는 것입니다 (존재하지 않는 것만). 따라서 모든 메소드를 비공개로하거나 데코레이터를 사용해야합니다. –

+0

@walheed khan get_class_methods ($ class)를 사용할 수 있지만 여전히 클래스 구조의 문제가 있습니다. – user784446