2013-02-27 2 views
1

나는 나는 현재과 같이 태클 오전 reoccuring 문제가 -PHP 디자인 패턴

플랫폼을 가지고 스크립트에 들어오는 POST 변수, 플랫폼이 목록에서 같은입니다

: X 박스, PS3, PC를 , MobileApp을, 모바일 게임 등 내 스크립트에 뭔가 다른 일을 할 수 있도록하려면 각기 다른 플랫폼에 대한

하지만 코드가 순간에 매우 비슷한 일을하고 싶은 경우에 나는 같은 것을 할

:

$platformArray = array(
    'ps3'=>array('displayName'=>'playstation 3','function'=>'funcPS3'), 
    'xbox'=>array('displayName'=>'Xbox','function'=>'funcXbox') 
) 
//similar amongst all platforms code on line below 
echo 'you have a :'.$platformArray[$_POST['platform']]['displayName'].' for playing  games'; 

call_user_func($platformArray[$_POST['platform']['function']); 

function funcPS3(){ 
    echo 'ps3 specific code'; 
} 

function funcXbox(){ 
    echo 'xbox specific code'; 
} 

내 코드에서 OOP 접근 방식으로 이동하고 싶습니다. o 지금은 내가하고있는 것처럼 배열이 아닌 데이터 저장 매체로 객체를 사용하지만, 때때로 코드에 속성을 정의해야 할 때가있다. 객체를 가지고 어떻게하면 좋을까?

+2

개체의 작동 방식을 살펴 보았습니까? [무엇을 시도 했습니까?] (http://whathaveyoutried.com)? – UnholyRanger

+0

그래, 기본 수준에 나는 그들이 일반적으로 당신이 설정할 수있는 함수와 함께 얻을 수있는 개인 내부 변수를 이해하고, 내가 미리 변수의 인스턴스를 여러 개로드 할 수 있다고 가정한다. 내가 참조 할 수 있다고 생각한다. $ {$ _ POST [ 'platform']} $ {$ _ POST [ 'platform']} -> myclassfunc();와 같은 일을 할 수 있습니까? ? 그것을 시도하지 않는 것에 대한 사과 내가 여기에 내 설치를 가지고 있지 않다면 – arcanine

+0

비슷한 부분이 미리 정의 된 기본 "플랫폼"클래스를 만든 다음 플랫폼을 상속하고 플랫폼의 일부 기능을 오버로드하는 XBOX/PS3/PC 클래스를 만든다. 특정 행동. –

답변

0

매우 순진한 OO 버전에서부터 "좋은"OO 코드로 간주되며, 다형성 동작을 사용하고 전역 상태를 피할 것입니다. 이 절차 적 코드를 통해 정말 그냥 래퍼 객체이기 때문에

1.하지 다형성 및이 글로벌 정적 데이터

이 꽤 나쁘다. 각 플랫폼 유형을 호출하는 함수 맵이 필요합니다.

class Platform {  
    private static $platformArray = array(
     'ps3' => array(
      'displayName'=>'playstation 3', 
      'function'=>'funcPS3' 
     ), 
     'xbox' => array(
      'displayName'=>'Xbox', 
      'function'=>'funcXbox' 
     ) 
    ); 

    private $type; 

    public function __construct($type) { 
     if (!array_key_exists($type, self::$platformArray)) { 
      throw new Exception("Invalid Platform type $type"); 
     } 
     $this->type = $type; 
    } 

    public function printCode() { 
     // This was a question embedded within your question, you can use 
     // http://php.net/manual/en/function.call-user-func.php 
     // and pass an instance with a method name.  
     return call_user_func(array($this, self::$platformArray[$this->type])); 
    } 

    private function funcPS3(){ 
     echo 'ps3 specific code'; 
    } 

    private function funcXbox(){ 
     echo 'xbox specific code'; 
    }  
} 

$plat = new Platform($_POST['platform']); 
$plat->printCode(); 

2. 다형성 ...하지만 여전히 각 문제에 대해 별도의 클래스를 만드는 글로벌 데이터

By creating a base class는 서브 클래스에서 동작을 구현할 수를 사용합니다. 큰 문제는 하위 클래스가 전역 레지스트리에 등록해야한다는 것입니다.

abstract class Platform { 
    abstract protected function getCode(); 
    public function printCode() { 
     echo $this->getCode(); 
    } 

    private function __construct() {} // so only factory can instantiate it 
    private static $platformArray = array(); 

    public static function create($type) { 
     if (!array_key_exists($type, self::$platformArray)) { 
      throw new Exception("Invalid Platform type $type"); 
     } 
     return new self::$platformArray[$type]; 

    }   

    public static function addPlatform($type, $ctor) { 
     if (!is_subclass_of($ctor, 'Platform')) { 
      throw new Exception("Invalid Constructor for Platform $ctor"); 
     } 
     self::$platformArray[$type] = $ctor; 
    } 
} 

class PlatformXBox extends Platform{ 
    protected function getCode() { 
     return 'xbox specific code'; 
    } 
} 
Platform::addPlatform('xbox', 'PlatformXBox'); 

class PlatformPs3 extends Platform { 
    protected function getCode() { 
     return 'ps3 specific code'; 
    } 
} 
Platform::addPlatform('ps3', 'PlatformPs3'); 

$plat = Platform::create($_POST['platform']); 
$plat->printCode(); 

3. 다형성, 아니 글로벌 데이터

By putting your code into a namespace

, 당신은 기본 클래스의 정적 코드를 방지하고 직접 클래스로 매핑 POST 매개 변수의 위험을 피할 수 있습니다.

namespace platform { 

interface IPlatform { 
    public function getDisplayName(); 
    public function getCode(); 
} 

class PlatformFactory { 
    static public function create($platformType) {   
     $className = "\\platform\\$platformType"; 
     if (!is_subclass_of($className, "\\platform\\IPlatform")){ 
      return null; 
     } 
     return new $className; 
    } 
} 

class Xbox implements IPlatform { 
    public function getDisplayName(){ 
     return 'xbox'; 
    } 
    public function getCode(){ 
     return 'xbox code'; 
    } 
} 

class Ps3 implements IPlatform { 
    public function getDisplayName(){ 
     return 'ps3'; 
    } 
    public function getCode(){ 
     return 'ps3 code'; 
    } 
} 

} 

지금 당신은 당신은 클래스라는 플랫폼을 만들 수 있습니다 다음

$platform = platform\PlatformFactory::create('xbox'); 
echo $platform->getCode() ."\n" ; 

$platform2 = platform\PlatformFactory::create('ps3'); 
echo $platform2->getDisplayName()."\n"; 

$noPlatform = platform\PlatformFactory::create('dontexist'); 
if ($noPlatform) { 
    echo "This is bad, plaftorm 'dontexist' shouldn't have been created"; 
} else { 
    echo "Platform 'dontexist' doesn't exist"; 
} 
+0

@ tereško이 방법으로 문제를 설명했습니다. 본질적으로, 코드를 취약하게 만들어서 게시 매개 변수에서 다른 유형의 클래스로 매핑해야합니다. –

+0

@ tereško 조언을 구해서 답변을 향상 시켰습니다. 제안 된 해결책으로 남아있는 문제를 알려주십시오. –

0

처럼 그 클래스를 사용할 수 있습니다 클래스 각 플랫폼에 대해 다른 방법 내 :

class platforms { 
    //Create your variables here, also called properties. 
    public $displayName; 

    //Create a function, also called a method for each platform you intent to use. 
    public function xboxPlatform(){ 
     //Code comes here what you want to do. 
    } 
} 

희망이 도움이됩니다.

+0

이것은 실제로 문제를 다루지 않습니다. POST 변수를 기반으로 메소드를 어떻게 호출 할 것입니까? –

+0

OOP 및 PDO를 사용하여 완벽하게 작동하는 자습서가 있습니다. [링크] https://docs.google.com/file/d/0B0fx_EGx3tG_SGFwcmZDMlJQbFE/edit?usp=sharing – Willem

+0

True 대답 1이 더 좋습니다. – Willem

4

다형성을 이해함으로써 시작하는 것이 좋습니다. This lecture 좋은 시작해야합니다. 당신은 몇 가지 플래그를 기반으로 동작을 만들려고 할 때

, 당신은 동일한 인터페이스와 함께 두 개의 클래스를 구현해야합니다

class Xbox 
{ 
    private $displayName = 'XBox 360'; 

    public function identify() 
    { 
     // Xbox-specific stuff 
     return ':::::::::::'. $this->displayName; 
    } 
} 

class PS3 
{ 

    private $displayName = 'Playstation 3'; 

    public function identify() 
    { 
     // playstation-specific stuff 
     return '+++'. $this->displayName . '+++'; 
    } 
} 

두 개의 클래스가 다른 일을 할 것 같은 이름와 방법이있다;

$platform = $_POST['platform']; 
// classes in PHP are case-insensitive 
// expected values would be: xbox, Xbox, ps3, pS3 
if (!class_exists($platform)) 
{ 
    echo "Platform '{$platform}' is not supported"; 
    exit; 
    // since continuing at this point would cause a fatal error, 
    // better to simply exit 
} 

$object = new $platform; 
echo $object->identify(); 

이 경우 기본적으로 어떤 유형의 플랫폼을 사용하는지 상관하지 않습니다. 당신이 알아야 할 것은 둘 모두 동일한 공용 인터페이스를 가지고 있다는 것입니다.이것을 "다형성 행동"이라고합니다.

+0

POST 매개 변수를 클래스에 매핑하는 것은 나쁜 취약점입니다. 그래서 사용자가 시스템의 모든 클래스를 인스턴스화하는 대신 허용 된 매개 변수의 레지스트리가 필요한 이유입니다. 이것은 내가 대답 할 때의 초기 생각 이었지만 취약한 방법을 제안하고 싶지 않았습니다. –

+0

@JuanMendes, 사실 "취약점"은 간단한 라우팅 메커니즘으로 처리 할 수 ​​있습니다. 클래스를 특정 네임 스페이스로 제한합니다. 그러므로 SO에서의 응답은 절대로 "프로덕션 읽기 코드"로 간주되지 않습니다. OP는 OOP를 이해하도록 요청했기 때문에 좋은 객체 지향 예제 (명백하고 쉽게 피할 수있는 결함이있는 예제) 대신에 전역 상태를 남용하는 절차 코드를 옹호 한 예제를 선택했습니다. –

+0

나는 동의한다, 나는 또한 최대량에 응답을 운동하기 위하여 시간을 걸리고 싶지 않았다. 그러나 귀하의 의견을 듣고 나서 OOP를 모른다는 가정하에 사람들을 피하기 위해 답을 개선하기로 결정했습니다. OOP를 이런 식으로 하나의 게시물에서 가르 칠 수는 없지만 업데이트 된 답변에 게시 한 단계가 순진한 설명에서 멋진 아이디어로 점차 옮겨 가면서 OP에 도움이되기를 바랍니다 (귀하의 아이디어와 명시적인 인터페이스) 이유를 설명하십시오. https://www.youtube.com/watch?v=-FRm3VPhseI 링크를 좋아했습니다. 나는 의존성 주입과 세계적인 상태를 피하는 것을 크게 믿는다. –