B-Teck!

お仕事からゲームまで幅広く

【PHP】PHPでオーバーロードみたいなことをしたかった。

PHPは実行時に型が決まるため、オーバーロードという仕組みがない。
似たような仕組みを実装したくて色々やってみた。

↓参考
PHPでオーバーロードしたい - チキン煮込みチーズミックス4辛


PHPオーバーロードに近いことを

  • 仮引数を用意して引数の数などに応じて分岐
  • __callを使って、「PHPオーバーロード」で分岐する


__callを使うのはあんまり趣味じゃないので仮引数を使う方法にする。

<?php
class fakeOverLoad{
    //公開するメソッド
     function gattai($i_exp1 = null,$i_exp2 = null){
 
         //分岐ロジック
         switch (true) {
             //引数なしの場合
             case $i_exp1 === null && $i_exp2 === null:
                 return $this->gattai_null();
                 break;

             //文字列の場合
             case is_string($i_exp1) && is_string($i_exp1):
                 return $this->gattai_s($i_exp1,$i_exp2);
                 break;

             //整数型の場合
             case is_int($i_exp1) && is_int($i_exp1):
                 return $this->gattai_i($i_exp1,$i_exp2);
                 break;

             //オブジェクトの場合
             case is_object($i_exp1) && $i_exp2 === null:
                 //オブジェクトのクラス名で分岐
                 if(get_class($i_exp1) === "testString"){
                    return $this->gattai_obj($i_exp1);
                    break;
                 }

             //該当なし
             default:
                 return "引数指定できてない";
                 break;
         }
     }
          
     //以下隠ぺいするメソッド
     //引数なし
     private function gattai_null(){
         return "引数なし\n";
     }

     //文字列
     private function gattai_s($i_exp1,$i_exp2){
         return $i_exp1.$i_exp2." 文字列\n";
     }

     //整数     
     private function gattai_i($i_exp1,$i_exp2){
         return $i_exp1 + $i_exp2." 数値\n";
     }
    
     //オブジェクト     
     private function gattai_obj($i_exp1){
         return $i_exp1->getA().$i_exp1->getB()." オブジェクト(プロパティの文字列)\n";
     }
}

//引数用オブジェクト
class testString{
    private $a;
    private $b;
    
    public function setData($i_exp1,$i_exp2){
        $this->a = $i_exp1;
        $this->b = $i_exp2;        
    }
    
    public function getA(){
        return $this->a;
    }
    
    public function getB(){
        return $this->b;
    }
}

 //以下検証用コード
 $a = "1";
 $b = "2";

 $objOverLoad = new fakeOverLoad;
 
 //引数なし呼び出し
 echo $objOverLoad->gattai();

 //文字列型呼び出し
 echo $objOverLoad->gattai((String)$a,(String)$b);

 //整数型呼び出し
 echo $objOverLoad->gattai((integer)$a,(integer)$b);
 
 //オブジェクト型呼び出し
 $objTest = new testString;
 $objTest->setData($a,$b);
 
 echo $objOverLoad->gattai($objTest);

/* 出力結果 */
// 引数なし
// 12 文字列
// 3 数値
// 12 オブジェクト(プロパティの文字列)
?>

メリット

  • 呼び出す側からは個々のメソッドが隠蔽されていることでgattaiに処理を集約できるので、共通の処理等を実装しやすい。

デメリット

  • gattai内で分岐しなきゃならないから分岐ロジックが太るし書くのめんどい。
  • PHPDocなんかで引数コメントが書きづらく、参照しづらい。

まぁ。
PHPならPHPっぽく書けってことだよね、うん。

【PHP】paizaラーニングで「長テーブルのうなぎ屋」を解いてみたよ

↓わかりづらいけど問題へのリンク

最近paizaに登録してみたので、まずは腕試しのできるラーニングから。

スカウト問題と違って、こっちは問題文も公開されてるし公式で答えも公開してるから、公開してもだいじょうぶだよね…?
エッ、今さら!?練習問題と具体的コード例によるTDD超入門。 - paiza開発日誌


汚いコードながらとりあえずは動作OKになりましたとさ。

公式の答えと同じようにリングバッファで書いてたはずだったのに、いつの間にか長さの余りを使ってゴリ押しで解くみたいになってた。
深く考えないことにした。

ちょいちょいブログにソースあげるようになって、管理もめんどくなってきたのでやはりGithubとGist導入必須案件なのでは。
やる気になったらソース書いてある箇所全部やろう。

<?php
//テーブルオブジェクト初期化
$objTables = null;

//標準入力取得
do{
    $s = trim(fgets(STDIN));
    if($s !== ""){
        $s = str_replace(array("\r\n","\r","\n"), '', $s);
        $s = explode(" ", $s);
        
        //初回のみテーブルサイズ・GROUP数設定
        if($objTables === null){
            $objTables = new unagiTable($s);
        }else{
            //二回目以降は来店
            $objTables->enterCustomer($s);
        }
    }
}while($s !== "");

//結果出力
echo $objTables->getResult();



class unagiTable{
    private $p_tableLen = 0;        //テーブルの長さ
    private $p_groupCnt = 0;        //グループ数
    private $p_tableStat = array(); //座席の状態
    
    //初期化
    function __construct($i_input){
        $this->p_tableLen = (int)$i_input[0];
        $this->p_groupCnt = (int)$i_input[1];
    }

    //来店
    function enterCustomer($i_input){
        $customerCnt = (int)$i_input[0];
        $tableNum = (int)$i_input[1];
        $seatNum = $this->getSeatNum($customerCnt,$tableNum);
        $this->sitSeatCustomer($seatNum);
    }    
    
    //対象の座席番号を配列で取得
    function getSeatNum($i_customerCnt,$i_tableNum){
        //必要なテーブルの終端を取得
        $tablesEnd = $i_customerCnt + $i_tableNum;
        
        //終端までループして必要な座席番号を取得
        for($i = $i_tableNum;$i !== $tablesEnd;$i++){
            $ret[] = $i % $this->p_tableLen;
        }
        
        return $ret;
    }
    
    //着席
    function sitSeatCustomer($i_seatNum){
        //対象の座席に人がいるかを確認
        foreach($i_seatNum As $value){
            if(array_key_exists($value,$this->p_tableStat) > 0 
                && $this->p_tableStat[$value] === true){
                return 0;
            }
        }
        
        //いなければ着席フラグを立てる
        foreach($i_seatNum As $value){
            $this->p_tableStat[$value] = true;
        }
        
        return 0;
    }
    
    //結果を取得
    function getResult(){
        $ret = 0;
        //着席フラグをカウント
        foreach($this->p_tableStat as $value){
            if($value === true){
                $ret++;
            }
        }
        return $ret;
    }
}
?>

【PHP】小数点以下の丸め/四捨五入

PHPで小数点以下の数値を扱ったり、数値を四捨五入する場合の関数。
 

・round(val [,precision, mode])

・floor(val)

・ceil(val)


val : 丸める値
(以下はroundのみ)
precision: 丸める桁数(正の値の場合は小数点以下の桁数。)
mode : 丸める際のモードを指定

定数 説明
PHP_ROUND_HALF_UP 小数点以下の桁がprecisionで指定した値になるように、次の帰趨にまとめる
PHP_ROUND_HALF_DOWN 小数点以下の桁がprecisionで指定した値になるように、次の帰趨にまとめる
PHP_ROUND_HALF_EVEN 小数点以下の桁がprecisionで指定した値になるように、次の偶数に丸める
PHP_ROUND_HALF_ODD 小数点以下の桁がprecisionで指定した値になるように、次の奇数に丸める

PHP_ROUND_HALF_EVEN、PHP_ROUND_HALF_ODDについての補足

対象の桁が5より小さければ切り捨て、5より大きければ切り上げを行い、
・ちょうどまんなかの5であればEVENの場合は偶数に近いほうに
・ちょうどまんなかの5であればODDの場合は奇数に近いほうに
丸め処理を行う。


<?php
print_r(round( 12345.6789)."\n");       // 1の位を四捨五入
print_r(round( 12345.6789,-1)."\n");    // 10の位を四捨五入
print_r(round( 12345.6789,-4)."\n");    // 10000の位を四捨五入
print_r(round( 12345.6789,1)."\n");     // 小数点第一位を四捨五入
print_r(round( 12345.6789,3)."\n");     // 小数点第三位を四捨五入
print_r(round( 1.55, 1,PHP_ROUND_HALF_UP)."\n");    // 小数点第一位をゼロから離れる方向に丸める
print_r(round( 1.55, 1,PHP_ROUND_HALF_DOWN)."\n");  // 小数点第一位をゼロに近づく方向に丸める
print_r(round( 1.55, 1,PHP_ROUND_HALF_EVEN)."\n");  // 小数点第一位を偶数に近づく方向に丸める
print_r(round( 1.55, 1,PHP_ROUND_HALF_ODD)."\n");   // 小数点第一位を奇数に近づく方向に丸める
print_r(ceil( 12345.6789)."\n");        // 小数点以下を切りあげ
print_r(floor(12345.6789)."\n");        // 小数点以下を切り捨て

//実行結果
//12346
//12350
//10000
//12345.7
//12345.679
//1.6
//1.5
//1.6
//1.5
//12346
//12345
?>