메뉴얼

EC-CUBE 2系

リファクタリングガイドライン

by TheVOS posted Sep 28, 2019
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
Extra Form
원문출처 http://svn.ec-cube.net/open_trac/wiki/EC...4%E3%83%B3

init 関数

init 関数は, クラスの初期化を目的する. ビジネスロジックの記述はしないこと

<?php
function init() {

    /**
     * NG ビジネスロジックの記述はしない
     */
    if (count($this->arrPayment) > 0) {
        $i = 0;
        foreach ($this->arrPayment as $val) {
            $this->payment[$i] = $val;
            $i++;
        }
    }

    /**
     * OK クラスの初期化のみ行う
     */
    $this->tpl_mainpage = 'index.tpl';
    $this->arrDISP = $masterData->getMasterData('mtb_disp');
}

action 関数

action 関数は MVC のコントローラにあたり以下の処理を記述する.

  • 条件分岐
  • VIEW からの入力
  • VIEW に渡すメンバ変数($this->variable_name)への代入
  • 宣言
  • ビジネスロジックの呼び出し

action 関数に, ビジネスロジックを直接記述したり, SQL を実行する処理を記述しないこと.

<?php
/**
 * action 関数のサンプル
 */
function action() {

    /** OK VIEW からの入力を処理する */
    $this->arrForm = $this->lfConvertParam($_POST);

    /** OK 入力に応じて条件分岐する */
    switch ($this->getMode()) {
    case 'edit':

        /** OK エラーの内容に応じて条件分岐する */
        $this->arrErr = $this->lfProductClassError($this->arrForm);
        if (empty($this->arrErr)){
            $this->tpl_mainpage = 'products/product_class_confirm.tpl';
            $this->lfProductConfirmPage($this->arrForm);
        } else {
            $this->doPreEdit($this->arrForm, false ,true);
        }
        break;

    case 'delete':
        $this->doDelete($this->arrForm);
        break;

    case 'disp':
        /** NG ビジネスロジックの記述をしてはならない */
        foreach ($this->arrForm as $key => $val) {
            $foo[$key] = $val;
        }

        /** NG SQLを実行する処理を記述してはならない */
        $objQuery = SC_Query::getSingletonInstance();
        $arrResults = $objQuery->select('*', 'table_name');

        $this->doDisp($this->arrForm);
        break;

    case 'complete':
        $this->registerProductClass($this->arrForm, $this->arrForm['product_id']);
        SC_Response_Ex::sendRedirect('complete.php');
        break;

    default:
    }
}

MODE パラメータ

$_POST['mode'] や $_GET['mode'] に対する条件分岐は, LC_Page::getMode() を使用し, switch 文で記述する.

<?php
/** OK switch 文で mode の分岐を行う */
switch ($this->getMode()) {
case 'disp':
    $this->doDisp($this->arrForm);
    break;

case 'complete':
    SC_Response_Ex::sendRedirect('complete.php');
    break;
default:
}

/** NG mode の条件分岐に if 文を使用してはならない */
if ($_POST['mode'] == 'disp') {
    $this->doDisp($this->arrForm);
} elseif ($_POST['mode'] == 'complete') {
    SC_Response_Ex::sendRedirect('complete.php');
}

ビジネスロジック

  • ページ間で重複する処理が存在する場合は, Helper などの共通クラスへ記述する
  • ページ固有の処理は, ローカル関数で記述する
  • 可能であれば, PHPUnit を使用してテストケースを残すこと
  • 宣言を除き, 引数や返り値が無く, すべて内部のメンバ変数で処理するような関数は極力作成しない
    • ステートレスな処理を心掛けること
<?php

/**
 * NG 引数ではなく, クラスのメンバ変数を使用して振舞いを変更する
 */
function lfSendMail() {
     $objPurchase = new SC_Purchase_Ex();
     $objPurchase->sendOrderMail($this->order_id)
}

/**
 * OK 引数で振舞いを変更できる
 */
function lfSendMail($order_id) {
     $objPurchase = new SC_Purchase_Ex();
     $objPurchase->sendOrderMail($order_id)
}

/**
 * NG 引数や返り値が無く, メンバ変数の値を直接変更している
 */
function lfConvertLoginPass(){
    if(strlen($this->arrForm['login_pass']) < 1 ) {
        return;
    }
    $this->arrForm['login_pass'] = trim($this->arrForm['login_pass']);
    $this->arrForm['login_pass1'] = $this->arrForm['login_pass'];
    $this->arrForm['login_pass2'] = $this->arrForm['login_pass'];
}

/**
 * OK ローカル関数内では, ローカル変数を使用することで, 拡張性, 保守性が向上し, ユニットテストも書きやすい
 */

$this->arrForm = $this->lfConvertLoginPass($this->arrForm);

function lfConvertLoginPass(&$arrForm){
    if(strlen($arrForm['login_pass']) < 1 ) {
        return;
    }
    $arrForm['login_pass'] = trim($arrForm['login_pass']);
    $arrForm['login_pass1'] = $arrForm['login_pass'];
    $arrForm['login_pass2'] = $arrForm['login_pass'];
    return $arrForm;
}

/**
 * ユニットテストの例.
 */
function testLfConvertLoginPass() {
    $login_pass = 'login_pass_value';
    $arrForm = array('login_pass' => $login_pass);

    $expected = array('login_pass' => $login_pass,
                      'login_pass1' => $login_pass,
                      'login_pass2' => $login_pass);

    $actual = lfConvertLoginPass($arrForm);

    $this->assertEquals($expected, $actual);
}
  • ループ処理などで, メンバ変数や, スーパーグローバル変数は直接使わない
<?php

/**
 * NG ループ処理で, メンバ変数やスーパーグローバル変数を直接扱っている
 */
foreach ($_POST['params'] as $key => $val) {
     $this->arrForm[$key] = $val;
}

/**
 * OK メンバ変数や, スーパーグローバル変数に作用するループ処理は, 別途関数を作成する
 */
$this->arrParams = $this->getParams($_POST['params']);

function getParams($arrParams) {
     $arrResults = array();
     foreach ($arrParams as $key => $val) {
         $arrResults[$key] = $val;
     }
     return $arrResults;
}

データベースアクセス

特に理由の無い場合は SC_Query::getSingletonInstance() を使用してインスタンスを取得すること

<?php

/**
 * NG PHP4 環境では, 新たなインスタンスが生成されてしまう
 */
$objQuery = new SC_Query();

/**
 * OK シングルトンが保証され, トランザクションの扱いが容易になる
 */
$objQuery = SC_Query::getSingletonInstance();

SQL 文を散乱させない. SELECT id, name, foo, bar FROM table_name と SELECT id, name, foo, bar, too FROM table_name が存在する場合は, 後者を共通関数にリファクタリングすること

<?php

/**
 * NG 類似した SQL を散乱させてはいけない
 */
$arrResults = $objQuery->select('id, name, foo, bar', 'table_name');
$arrResult2 = $objQuery->select('id, name, foo, bar, too', 'table_name', 'too = ?', $arrParams['too']);

/**
 * OK カラム名や, WHERE の違いなどは共通関数で吸収する
 */
function getResults($arrParams = array()) {
    $where = '';
    $arrValues = array();
    if (isset($arrParams['too'])) {
        $where .= 'too = ?';
        $arrValues[] = $arrParams['too'];

    }
    $objQuery = SC_Query::getSingletonInstance();
    $arrResults = $objQuery->select('*', 'table_name', $where, $arrValues);
    return $arrResults;
}
$arrResults = getResults();
$arrResults2 = getResults($arrParams);

INSERT/UPDATE/DELETE は, SC_Query::insert(), SC_Query::update(), SC_Query::delete() を使用し, SC_Query::query() は使用しないこと

<?php

/** NG SC_Query::query() は使用しない */
$objQuery = SC_Query::getSingletonInstance();
$objQuery->query('INSERT INTO table_name (col1, col2) VALUES (?, ?)', arrary($col1, $col2));

/** OK SC_Query::insert(), SC_Query::update(),  SC_Query::delete() を使用する */
$objQuery = SC_Query::getSingletonInstance();
$objQuery->insert('table_name', array('col1' => $col1,
                                      'col2' => $col2));

LIMIT, OFFSET は SC_Query::setLimit(), SC_Query::setLimitOffset() を使用すること.

<?php

/** NG LIMIT, OFFSET を直接使用しない */
$objQuery = SC_Query::getSingletonInstance();
$arrResults = $objQuery->getAll('SELECT * FROM table_name WHERE del_flg = 0 LIMIT 10 OFFSET 5');

/** OK SC_Query::setLimit(), SC_Query::setLimitOffset() を使用する */
$objQuery = SC_Query::getSingletonInstance();
$objQuery->setLimitOffset(10, 5);
$arrResults = $objQuery->select('*', 'table_name', 'del_flg = ?', array('0'));

RDBMS の可搬性向上のため USING 句は使用しないこと

<?php

/** NG USING 句は使用しない */
$objQuery = SC_Query::getSingletonInstance();
$arrResults = $objQuery->select('T1.*', 'table_name T1 JOIN table2_name T2 USING(col)');

/** OK ON 句 を使用する */
$objQuery = SC_Query::getSingletonInstance();
$arrResults = $objQuery->select('T1.*', 'table_name T1 JOIN table2_name T2 ON T1.col = T2.col');

入力チェック

入力チェック用のクラスには, SC_FromParam と SC_CheckError が存在するが, 極力 SC_FormParam を使用すること

端末種別の判別

Net_UserAgent_Mobile::isMobile() や MOBILE_SITE 定数など存在するが, SC_Display_Ex::detectDevice() に統一する

スーパーグローバル変数

$_POST や $_GET の値は, 必ず入力チェック後に使用する. SC_FormParam を使用していれば, SC_FormParam::getHashArray() で取得できる

<?php

/** NG $_POST の値を入力チェックせずに使用する */
$this->register($_POST);

/** OK 必ず入力チェックを行う */
$objFormParam = new SC_FormParam();
$objFormParam->addParam('商品規格ID', 'product_class_id', INT_LEN, 'n', array('EXIST_CHECK', 'MAX_LENGTH_CHECK', 'NUM_CHECK'));
$objFormParam->setParam($_POST);
$objFormParam->convParam();
$arrErr = $objFormParam->checkError()
if (SC_Utils_Ex::isBlank($arrErr)) {
     // 入力チェック後の値が取得可能
     $arrForm = $objFormParam->getHashArray();
}
$this->register($arrForm);

$_SESSION は, SC_CartSession クラス等, セッションを扱うビジネスロジックを通じて使用するのが望ましい.

どうしても, グローバル変数を使用したい場合は, global キーワードは使用せず, $GLOBALS を使用すること.

<?php
/**
 * NG global キーワードの使用すると, 変数名衝突の原因となる
 */
function globalSample() {
    global $conn;

    // 外部からは $conn という変数を使用しているのがわからない
    if (is_null($conn)) {
        $conn = new ClassName();
    }
}

/**
 * OK $GLOBALS を使用すると, ローカル変数との衝突の心配は無い
 */
function globalSample() {
    if (is_null($GLOBALS['_conn'])) {
        $GLOBALS['_conn'] = new ClassName();
    }
}

変数名

変数名で, どんなデータか識別できるよう考慮すること

<?php

/**
 * NG 一見して, どんなデータが格納されているかわからない
 */
$arrRet = getProducts();

/**
 * OK 商品データの配列だと, 変数名で判別可能
 */
$arrProducts = getProducts();

リテラルを格納する (つまり配列・オブジェクト以外の) 変数名は, すべて小文字を使用し, アンダーバーで区切ること

<?php

/**
 * リテラルを格納する変数名は, 連想配列の添字で使用されることも考慮し
 * アンダーバー区切りの方が扱いやすい
 */

/**
 * NG
 */
$productId = getProductId();

/**
 * OK
 */
$product_id = getProductId();

1行の文字数/行数

  • 1行の文字数は80文字までにすることを目指すこと. すなわち, コードの長さを現実的な範囲で80文字までにおさめるよう努力すべきです. しかしながら, 場合によっては少々長くなってしまってもかまいません.
  • 1関数の行数は多くても200行程度に留めるのが望ましい. これ以上行数が増えてしまう場合は, 関数を分割する等, コーディングの見直しを行ってください

PHPDoc コメント

関数の PHPDoc コメントは必ず記述する.

  • 関数の説明
  • 引数
    • 引数の無い関数は省略可能
  • 返り値
    • 返り値が無くても void を明記すること

非推奨機能

error_reporting(E_ALL) で, エラー及び警告が出力されないようコーディングすること.

PHP5.3 で非推奨となっている関数は使用しないこと.

  • call_user_method() (かわりに call_user_func() を使用します)
  • call_user_method_array() (かわりに call_user_func_array() を使用します)
  • define_syslog_variables()
  • dl()
  • ereg() (かわりに preg_match() を使用します)
  • ereg_replace() (かわりに preg_replace() を使用します)
  • eregi() (かわりに preg_match() で 'i' 修正子を使用します)
  • eregi_replace() (かわりに preg_replace() で 'i' 修正子を使用します)
  • set_magic_quotes_runtime() およびそのエイリアスである magic_quotes_runtime()
  • session_register() (かわりにスーパーグローバル $_SESSION を使用します)
  • session_unregister() (かわりにスーパーグローバル $_SESSION を使用します)
  • session_is_registered() (かわりにスーパーグローバル $_SESSION を使用します)
  • set_socket_blocking() (かわりに stream_set_blocking() を使用します)
  • split() (かわりに preg_split() を使用します)
  • spliti() (かわりに preg_split() で 'i' 修正子を使用します)
  • sql_regcase()
  • is_dst を mktime() に渡すこと。 かわりにタイムゾーン処理用の新しい関数を使用します。

以下の機能も, PHP5.3.x で非推奨となっているが, PHP4互換のために使用しても良い EC-CUBE 2.12.0 から PHP4 は非対応となりました.

  • new の返り値を参照で代入すること
  • 呼び出し時の参照渡し

参考 http://www.php.net/manual/ja/migration53.deprecated.php

URL のファイルパス部の取得は $_SERVER['PHP_SELF'] を使わず、代わりに $_SERVER['SCRIPT_NAME'] を使用する。(参考: #1717)

Facebook [ko]댓글 


  1. 클래스의 사용

    클래스의 사용

    인스턴스의 생성 클래스가 선언되고 나면, 선언된 클래스로부터 인스턴스를 생성할 수 있습니다. PHP에서는 new 키워드를 사용하여 인스턴스를 생성할 수 있습니다. 이때 클래스 이름을 통해 생성자로 필요한 인수를 전달할 수 있습니다. 문법 $객체이름 = new...
    Date2019.10.03 Category클래스 Views93
    Read More
  2. 클래스의 구조

    클래스의 구조

    클래스의 구조 PHP에서 클래스는 class 키워드를 사용하여 다음과 같이 선언합니다. 문법 class 클래스이름 { 클래스의 프로퍼티과 메소드의 정의; } PHP에서 클래스의 이름을 생성할 때는 반드시 다음 규칙을 지켜야만 합니다. 1. 클래스의 이름은 숫자와의 ...
    Date2019.10.03 Category클래스 Views35
    Read More
  3. 클래스와 객체의 기초

    クラス(class)とオブジェクト(object) オブジェクト(object)とは、実生活では、我々が認識することができるもので理解することができます。 これらのオブジェクトの状態(state)と行動(behavior)は、それぞれのプロパティ(property)とメソッド(met...
    Date2019.10.03 Category클래스 Views56
    Read More
  4. EC-CUBE:SC_FormParamクラスによるパラメーターチェック方法

    EC-CUBE:SC_FormParamクラスによるパラメーターチェック方法

    EC-CUBE에 대한 인터넷상에서 아직 정보가 많이 부족합니다. 예를 들어 플러그인 작성에 원래 폼을 만들어도 SC_FormParam 클래스 를 사용하여 어떻게 확인하면 좋은 것인지 조사해도 좀처럼 나오지 않습니다. 그래서 내가 독자적으로 조사한 속에서 조금씩 정...
    Date2019.10.03 CategoryEC-CUBE 2.x Views119
    Read More
  5. EC-CUBE2.12 運用マニュアル

    EC-CUBE ver2120 2121 2122 運用マニュアル1 Page EC-CUBE Ver2120 Ver2121 Ver2122 運用マニュアル 2012年11月28日 Thi s document is licensed under a Creative Commons 表示 - 継承 2 1 日本 License THEVOS ECO LAB Inc EC-CUBE ver2120 2121 212...
    Date2019.09.29 CategoryEC-CUBE 운용 설명서 Views62
    Read More
  6. 単体テストガイドライン

    単体テストガイドライン

    本ガイドラインはEC-CUBEの単体テストをPHPUnitを使って行う上でのガイドラインを株式会社SHIFT様(http://www.shiftinc.jp/)のご協力によりまとめたものとなります。 各クラス共通のガイドライン1. テストを含めたフォルダ構成テストコードを含んだフォルダ構...
    Date2019.09.28 CategoryEC-CUBE 2系 Views86
    Read More
  7. リファクタリングガイドライン

    リファクタリングガイドライン

    init 関数init 関数は, クラスの初期化を目的する. ビジネスロジックの記述はしないこと <?php function init() { /** * NG ビジネスロジックの記述はしない */ if (count($this->arrPayment) > 0) { $i = 0; foreach ($this->arrPayment as $val) { $this->pa...
    Date2019.09.28 CategoryEC-CUBE 2系 Views153
    Read More
  8. EC-CUBE標準規約

    EC-CUBE標準規約

    基本的に Zend Framework PHP 標準コーディング規約 に順ずる.以下, 要点及び相違点を規定する. また, コーディングに際して, 以下のガイドラインに沿うことが望ましい EC-CUBE標準規約 > リファクタリングガイドライン PHPUnitを利用した単体テストを行う際は...
    Date2019.09.28 CategoryEC-CUBE 2系 Views154
    Read More
  9. デフォルトのtitleを任意のものに変更する方法

    EC-CUBE 3.Xでデフォルトでtitle部分に表示されるものを任意で削除・変更したり、あらかじめ用意されているページのページ名(テンプレート名)を任意のものに変更する方法です。 ※紹介している内容はEC-CUBEのVersion 3.0.10で動作確認したもので、デフォルト...
    Date2019.04.10 CategoryEC-CUBE 3.x Views227
    Read More
  10. titleの並びや区切り記号を変更する方法

    EC-CUBE 3.Xは、デフォルトのテンプレートだとtitle表示が「ショップ名 / ページ名」という形になっていますが、それを任意の並びにしたり区切り記号を変更したりする方法です。 ※紹介している内容はEC-CUBEのVersion 3.0.10で動作確認したもので、デフォルト...
    Date2019.04.10 CategoryEC-CUBE 3.x Views96
    Read More
  11. 商品数や階層に関係なく全カテゴリーを表示させる方法

    EC-CUBEの備忘録。デフォルトのテンプレートだとサイドに表示されている商品カテゴリーですが、商品登録がない場合はカテゴリー名が表示されず、商品が登録されていたとしても親カテゴリーのページでなければ子カテゴリー名は表示されないようになっています。...
    Date2019.04.10 CategoryEC-CUBE 2.x Views260
    Read More
  12. 商品名などで長くなったテキストを省略する方法

    引き続きEC-CUBEの備忘録です。商品のタイトルや紹介文が指定した文字数以上になったときに「...」などを表示して、見栄えを揃える方法です。jQueryを使うとかCSSのtext-overflowなんかでも同じ事はできますが、Smartyを使って実装するものになります。 ※EC-CU...
    Date2019.04.10 CategoryEC-CUBE 2.x Views45
    Read More
  13. サイトデザインをPCで統一させる方法

    EC-CUBEはもともとスマートフォンやモバイル用のテンプレートが用意されており、それぞれのデバイスで閲覧すると各テンプレートに振り分けらるようになっているのですが、それを無効にする方法です。この機能自体は良いと思うのですが、例えばモバイルまで手が...
    Date2019.04.10 CategoryEC-CUBE 2.x Views52
    Read More
  14. 商品ステータスを変更・追加する方法

    EC-CUBE自体をまだあまり触ったこともなければ、そんなに頻繁に使わないのもあって、しばらくすると簡単なことでもいろいろと忘れてしまうので備忘録。デフォルトだと「NEW」とか「残りわずか」などで登録されている商品ステータスを任意のものに変更・追加す...
    Date2019.04.10 CategoryEC-CUBE 2.x Views62
    Read More
  15. 新規作成したページURLから「user_data」を消す方法とURLを出力するテンプレートタグ

    EC-CUBE 3.Xではもともと用意されているページを利用するだけでなくオリジナルで新規ページを追加することもできるのですが、その場合作成したページのURLに「user_data」が付与されています。この「user_data」という部分をURLから消す方法とそれに関連して新...
    Date2019.04.10 CategoryEC-CUBE 3.x Views863
    Read More
  16. 메일 사용자 설명서

    메일 사용자 설명서

    원 포인트 가이드메일 소프트에 다음 정보를 설정하십시오. 메일 서버 (POP)sv11.star.ne.jp메일 서버 (SMTP)sv11.star.ne.jp계정 (사용자 이름)만든 계정 이름 (@이후도 포함)비밀번호설정 한 패스워드
    Date2019.03.29 Category메일 서비스 Views61
    Read More
  17. 페이스북위젯 삽입하기

    페이스북 위젯을 삽입하는 방법을 알아보겠습니다. 1. 페이스북 위젯을 설정하는 곳으로 갑니다. ( https://developers.facebook.com/docs/plugins/page-plugin ) 2. 원하는 위젯모양을 만듭니다. 밑의 이미지를 보시면 쉽게 이해가 되실꺼예요. 3. 설정이 끝...
    Date2018.12.15 Category팁 & 노하우 나눔 Views45
    Read More
  18. 구글 캘린더 합치기

    구글 캘린더로 일정관리를 하는 사람이라면 한번쯤 여러개로 나눠진 캘린더를 하나로 합쳐야 할 때가 생깁니다. 저같은 경우는 처음에 일정관리에 심취해서 캘린더 수를 아주 자세하게 여러개로 나눠 놨었죠. 그러나 최근에서야 단순함의 미학과 효율성에 눈을...
    Date2018.12.12 Category팁 & 노하우 나눔 Views427
    Read More
  19. THEVOS Youtube BOARD SKIN 사용 설명

    THEVOS Youtube BOARD SKIN 사용 설명

    [ 스킨 기능 ] - 사용자 정의 자동추가 게시판 스킨을 "INSP 유튜브"으로 변경하고 사용자정의 eid(dex_embed_srl)가 없을겨우 자동으로 추가됨 - 기존게시판에서도 사용가능 ㄴ 게시판에 필요한 사용자 정의는 "thevos_extv_youtube_code" 이다. ㄴ 하지만 sk...
    Date2018.11.11 Category메뉴얼 Views116
    Read More
Board Pagination Prev 1 2 Next
/ 2