PHPの継承について1から勉強しなおす

継承。わかっているようで全くわかっていなかったので、基礎から勉強しなおしました。

まずはこちらをご覧ください。

<?php
class AnalysisFile {
    public function getFile($file) {
        $row = 1;
        if (($handle = fopen($file, "r")) !== FALSE) {
            while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
                $num = count($data);
                echo "$num fields in line $row\n";
                $row++;
                print_r($data);
            }
            fclose($handle);
        }
    }
}

$af = new AnalysisFile();
$af->getFile("test.csv");

PHPマニュアル「fgetcsv」の例*1をほぼ引用。CSVファイルの全てのコンテンツを読み込み、表示しているだけです。でもこれ、正直言ってわかりにくい(と思うのは私だけ?)ので、もうちょっとわかりやすく書き直してみます。

っで、修正したものがこちらになります。

<?php
class AnalysisFile {
    public function __construct() {
        $this->GetCount = 1;
    }

    public function getCount() {
        return $this->GetCount;
    }

    public function getFile($file) {
        if (($handle = fopen($file, "r")) !== FALSE) {
            $this->readFile($handle);
            fclose($handle);
        }
    }

    private function readFile($handle) {
        $row = $this->getCount();
        while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
            $num = count($data);
            echo "$num fields in line $row\n";
            $row++;
            $this->printArray($data);
        }
    }

    private function printArray($array) {
        print_r($array);
    }
}

$af = new AnalysisFile();
$af->getFile("test.csv");

多少強引にやってますが。まぁでもなんとなくオブジェクト指向っぽい(小並感)

ここまで書き終えると、こんな要望が来たとします。

「Web上にあるCSVファイルを取得して、保存して、同じように解析して。あっ、今までの機能は残しておいてね」

おk、把握した。getFile()に、ファイルが渡されたときとURLが渡されたときとで分けるよう処理を追加しよう。If文で、正規表現も使って・・・できた、デバッグするぞー、ってあれ?落ちた?どこで?と、とりあえず前の状態に戻して・・・。

なんてことをやっていたらアホです。えぇ、過去の私です、アホでした。こういうときは「継承」を使うのが便利、だそうです。早速修正してみましょう。

<?php
class AnalysisFile {
    public function __construct() {
        $this->GetCount = 1;
    }

    public function getCount() {
        return $this->GetCount;
    }

    public function getFile($file) {
        if (($handle = fopen($file, "r")) !== FALSE) {
            $this->readFile($handle);
            fclose($handle);
        }
    }

    private function readFile($handle) {
        $row = $this->getCount();
        while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
            $num = count($data);
            echo "$num fields in line $row\n";
            $row++;
            $this->printArray($data);
        }
    }

    private function printArray($array) {
        print_r($array);
    }
}

class AnalysisDownloadFile extends AnalysisFile {
    public function getFile($url) {
        $file = $this->downloadFile($url);
        parent::getFile($file);
    }

    public function downloadFile($url) {
        $file = file_get_contents($url);
        $filePath = "/var/www/html/csv/downloadfile.csv";
        file_put_contents($filePath, $file);
        return $filePath;
    }
}

$af = new AnalysisFile();
$adf = new AnalysisDownloadFile();
$af->getFile("/var/www/html/csv/test.csv");
$adf->getFile("http://hoge/piyo.csv");

というようにすると、元のクラスを一切変更することなく機能追加ができるわけです。はぁ、すごく便利。