Help us understand the problem. What is going on with this article?

PHPで使うGoFパターン ひとり Advent Calendar - ストラテジー

More than 5 years have passed since last update.

ストラテジーってなに?

戦略って意味ですね。実行時の状況ごとにアルゴリズムを切り替える…… というデザインパターンです。この記事の想定読者であるPHPプログラマが主に使うPHPやJavaScriptではクロージャなんかも有るのでオブジェクト指向のこのパターンを大真面目に適用することも少いかも知れませんが一応基礎ということで。
JDKや.NETFrameworkの中だと、ソートする時のComparatorとかもこのパターンだと思います。

<?php
function buildEscaper ( $type ) {
  $type = strtolower ( $type );
  if     ( $type == 'html'  ) return function ( $s ) { return htmlspecialchars ( $s, ENT_QUOTES ); }
  elseif ( $type == 'url'   ) return function ( $s ) { return urlencode ( $s ); }
  elseif ( $type == 'regex' ) return function ( $s ) { return preg_quote ( $s ); }
  elseif ( $type == 'sql'   ) return function ( $s ) { return mysql_real_escape_string ( $s ); }
  else   throw new Exception ( 'そんなの有りません|' . $type );
}

$h = buildEscaper ( 'html' );
print $h ( '<html>' );

ストラテジーの構造

  • コンテキスト - 使用者
  • ストラテジーインターフェース - インターフェースね
  • 実ストラテジー - 実際のアルゴリズム

それぞれのクラス構造

<?php
/* Context */
class TemplateEngine {
  private $_Escaper = null;
  private $_TemplatePath = null;
  private $_Params = array ();

  public function __construct ( $escaper ) {
    if ( !( $escaper instanceof IEscaper ) )
      throw new Exception ( 'Escaperじゃないもん' );
    $this->_Escaper = $escaper;
  }

  public function setTemplatePath ( $path ) {
    if ( !is_file ( $path ) )
      throw new Exception ( 'そんなファイル無いもん' );
  }

  public function assign ( $s ) {
    print $this->_Escaper->escape ( $s ); 
  }

  public function parse () { 
    ob_start ();
    include $this->_TemplatePath;
    return ob_get_clean();
  }

  public function setParam ( $key, $val ) {
    $this->_Params[$key] = $val;
  }

  public function getParam ( $key ) {
    return $this->_Params[$key];
  }
}

/* Strategy Interface */
interface IEscaper {
  public function escape();
}

/* Strategy */
class HTMLEscaper implements IEscaper {
  public function escape ( $s ) { return htmlspecialchars ( $s, ENT_QUOTES ); }
}

class URLscaper implements IEscaper {
  public function escape ( $s ) { return urlencode ( $s ) ; }
}

class RegExpEscaper implements IEscaper {
  public function escape ( $s ) { return preg_quote ( $s ) ; }
}

class SQLEscaper implements IEscaper {
  public function escape ( $s ) { return mysql_real_escape_string ( $s ) ; }
}

HTMLテンプレート

<html>
<body>
<table>
<?php foreach ( $this->getParam ( 'arr' ) as $row ): ?>
<tr>
  <td><?php $this->assign ( $row->id ) )?></td>
  <td><?php $this->assign ( $row->name ) )?></td>
</tr>
<?php endforeach; ?>
</table>
</body>
</html>

SQLテンプレート

SELECT * FROM tbl WHERE name = '<?php $this->assign ( $this->getParam('name') ) ?>'

実際に使うところ

<?php
$html = new TemplateEngine ( new HTMLEscaper() );
$html->setTemplatePath ( '/path/to/html_template' );
$html->setParam ( array (
  'arr' => array ( 
    (object)array ('id' => 1, 'name' => '<script>alert("name1");</script>' ) ,
    (object)array ('id' => 2, 'name' => 'name2' ) ,
    (object)array ('id' => 3, 'name' => 'name3' ) ,
  ),
));
print $html->parse();

$sql = new TemplateEngine ( new SQLEscaper () );
$sql->setTemplatePath ( '/path/to/sql_template' );
$sql->setParam ( array ( 'name' => "n'am'e" ) );
print $sql->parse();
t_ishida
404 motivation not found 技術系同人誌書いたりしています。 でざぱたん: デザインパターン擬人化 セキュリティホールたん物語: セキュリティホール擬人化 http://alice-books.com/item/list/all?circle_id=3086
http://tech.aainc.co.jp/archives/author/ishida
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away