ためすう

PHP で正規表現を使う

2018-10-21

目的

php で下記の条件で判定を行いたい時がありました。

  • ファイル名で拡張子が jpg, jpeg, gif, png 
  • .で始まらない

explode を使って配列にしてファイル名を文字列比較してたのですが、正規表現だともっと簡単に出来そうなので正規表現でやってみました。

正規表現でやってみる

<?php

$files = [
    'test.jpg',
    'test.jpeg',
    '222test.gif',
    '333test.png',
    '.test.jpg'
];

foreach ($files as $v) {
    echo $v . "\n";
    if (preg_match("/^[^\.]+\.(jpe?g|gif|png)$/", $v)) {
        echo "A match was found.";
    } else {
        echo "A match was not found.";
    }
echo "\n\n";
}

実行結果

test.jpg
A match was found.

test.jpeg
A match was found.

222test.gif
A match was found.

333test.png
A match was found.

.test.jpg
A match was not found.

今回使用した正規表現パターンについて

| | | |-|— | |^ |行頭 | |$ |行末 | |[^abc] |a、b、c以外の1文字 | |+ |1回以上の繰り返し | |? |0回または1回の出現 |

参考URL

PHP でデザインパターン (Abstract Factory)

2018-10-21

Abstract Factory パターンとは

具体的なクラスを明確にすることなく、関連し合うオブジェクトの集まりを生成するパターン

オブジェクト指向プログラミングでは、具体的なクラスではなくインターフェースや抽象化されたクラスのAPIに対してプログラミングすることが重要になります

Abstract Factory パターンのメリット

  • 具体的なクラスをクライアントから隠蔽する
  • 利用する部品群の整合性を保つ
  • 部品群の単位で切り替えができる

実装例

<?php
interface DaoFactory
{
    public function createItemDao();
    public function createOrderDao();
}

class DbFactory implements DaoFactory
{
    public function createItemDao()
    {
        return new DbItemDao();
    }

    public function createOrderDao()
    {
        return new DbOrderDao($this->createItemDao());
    }
}

class MockFactory implements DaoFactory
{
    public function createItemDao()
    {
        return new MockItemDao();
    }

    public function createOrderDao()
    {
        return new MockOrderDao();
    }
}

interface ItemDao
{
    public function findById($item_id);
}

interface OrderDao
{
    public function findById($order_id);
}

class DbItemDao implements ItemDao
{
    const ITEM_DATA = [
        1 => '商品1',
        2 => '商品2',
        3 => '商品3',
    ];
    private $items;
    public function __construct()
    {
        $this->items = [];

        foreach (self::ITEM_DATA as $key => $val) {
            $item = new Item($key, $val);
            $this->items[$item->getId()] = $item;
        }
    }

    public function findById($item_id)
    {
        if (array_key_exists($item_id, $this->items)) {
            return $this->items[$item_id];
        }

        return null;
    }
}

class DbOrderDao implements OrderDao
{
    const ORDER_DATA = [
        1 => '3',
        2 => '1,3',
        3 => '1,2,3',
        4 => '2',
        5 => '2,3',
    ];

    private $orders;
    public function __construct(ItemDao $item_dao)
    {
        $this->orders = [];
        foreach (self::ORDER_DATA as $key => $val) {
            $order = new Order($key);
            foreach (explode(',', $val) as $item_id) {
                $item = $item_dao->findById($item_id);
                if (!is_null($item)) {
                    $order->addItem($item);
                }
            }
            $this->orders[$order->getId()] = $order;
        }
    }

    public function findById($order_id)
    {
        if (array_key_exists($order_id, $this->orders)) {
            return $this->orders[$order_id];
        }

        return null;
    }
}

class MockItemDao implements ItemDao
{
    public function findById($item_id)
    {
        $item = new Item($item_id, 'dummy item');
        return $item;
    }
}

class MockOrderDao implements OrderDao
{
    public function findById($order_id)
    {
        $order = new Order($order_id);
        $order->addItem(new Item('99', 'dummy item 99'));
        $order->addItem(new Item('99', 'dummy item 99'));
        $order->addItem(new Item('98', 'dummy item 98'));

        return $order;
    }
}

class Item
{
    private $id;
    private $name;

    public function __construct($id, $name)
    {
        $this->id = $id;
        $this->name = $name;
    }

    public function getId()
    {
        return $this->id;
    }

    public function getName()
    {
        return $this->name;
    }
}

class Order
{
    private $id;
    private $items;

    public function __construct($id)
    {
        $this->id = $id;
        $this->items = [];
    }

    public function addItem(Item $item)
    {
        $id = $item->getId();
        if (!array_key_exists($id, $this->items)) {
            $this->items[$id]['object'] = $item;
            $this->items[$id]['amount'] = 0;
        }
        $this->items[$id]['amount']++;
    }

    public function getItems()
    {
        return $this->items;
    }

    public function getId()
    {
        return $this->id;
    }
}

// // DbFactory
$factory = new DbFactory();
// MockFactory
// $factory = new MockFactory();
$item_id = 1;
$item_dao = $factory->createItemDao();
$item = $item_dao->findById($item_id);
//
echo sprintf("ITEM ID: %d Name: %s\n", $item_id, $item->getName());

$order_id = 3;
$order_dao = $factory->createOrderDao();
$order = $order_dao->findById($order_id);

echo sprintf("ORDER ID: %d\n", $order_id);

foreach ($order->getItems() as $item) {
    echo sprintf("ITEM NAME: %s, AMOUNT: %d\n", $item['object']->getName(), $item['amount']);
}

参考

PHP でデザインパターン (Flyweight)

2018-10-20

Flyweight パターンのメリット

一度インスタンス化したオブジェクトを使い回し、生成されるオブジェクトの数やリソースの消費を抑えます

Flyweightパターンでは、メモリ以外のリソースも節約することができます。たとえば、インスタンスを生成する時間がそうです。インスタンスを生成することは、非常に時間がかかる処理の1つです。

実装例

<?php

class Item
{
    private $code;
    private $name;
    private $price;

    public function __construct($code, $name, $price)
    {
        $this->code = $code;
        $this->name = $name;
        $this->price = $price;
    }

    public function getCode()
    {
        return $this->code;
    }

    public function getName()
    {
        return $this->name;
    }

    public function getPrice()
    {
        return $this->price;
    }
}

class ItemFactory
{
    const DATA = [
        ['ITEM_CODE_001', 'ITEM_NAME_001', 3800],
        ['ITEM_CODE_002', 'ITEM_NAME_002', 1500],
        ['ITEM_CODE_003', 'ITEM_NAME_003', 800],
    ];

    private $pool;
    private static $instance = null;

    private function __construct()
    {
        $this->buildPool();
    }

    public static function getInstance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new ItemFactory();
        }

        return self::$instance;
    }

    public function getItem($code)
    {
        if (array_key_exists($code, $this->pool)) {
            return $this->pool[$code];
        }
        return null;
    }

    public function buildPool()
    {
        $this->pool = [];
        foreach (self::DATA as $row) {
            $item = new Item($row[0], $row[1], $row[2]);
            $this->pool[$row[0]] = $item;
        }
    }

    public final function  __clone()
    {
        throw new RuntimeException();
    }
}

$factory = ItemFactory::getInstance();
$items = [];
$items[] = $factory->getItem('ITEM_CODE_001');
$items[] = $factory->getItem('ITEM_CODE_002');
$items[] = $factory->getItem('ITEM_CODE_003');

// true
var_dump($items[0] === $factory->getItem('ITEM_CODE_001'));

// false
var_dump($items[0] === new Item('ITEM_CODE_001', 'ITEM_NAME_001', 3800));

参考

PHPでデザインパターン (Adapter)

2018-10-20

Adapter パターンとは

  • 「すでに提供されているもの」と「必要なもの」の間の「ずれ」を埋めるようなデザインパターン
  • Adapter パターンは、既存のクラスにはまったく手を加えずに、目的のインターフェース(API)にあわせようとするものです。

Adapter パターンには下記の2種類があります

  • クラスによる Adapter パターン (継承を使ったもの)
  • インスタンスによる Adapter パターン (委譲を使ったもの)

実装例

<?php

class ShowFile
{
    private $filename;

    public function __construct($filename)
    {
        $this->filename = $filename;
    }

    public function showPlain()
    {
        echo file_get_contents($this->filename);
    }

    public function showHighlight()
    {
        highlight_file($this->filename);
    }
}

interface DisplaySourceFile
{
    public function display();
}

// $filepath = __FILE__;
// $show_file = new ShowFile($filepath);
// $show_file->showPlain();
// echo "------\n";
// $show_file->showHighlight();

// 継承を使ったパターン
class DisplaySourceFileImpl extends ShowFile implements DisplaySourceFile
{
    public function __construct($filename)
    {
        parent::__construct($filename);
    }

    public function display()
    {
        parent::showHighlight();
    }
}

$show_file = new DisplaySourceFileImpl(__FILE__);
$show_file->display();

// 委譲を使ったパターン
class DisplaySourceFileImpl2 implements DisplaySourceFile
{
    private $show_file;

    public function __construct($filename)
    {
        $this->show_file = new ShowFile($filename);
    }

    public function display()
    {
        $this->show_file->showHighlight();
    }
}

$show_file = new DisplaySourceFileImpl2(__FILE__);
$show_file->display();

所感

既存のクラスに変更を加えたくない時や、既存のクラスを変更できない場合の選択肢の1つになると思います。

参考

PHP でデザインパターン (Iterator)

2018-10-15

Iterator パターンとは

  • リストの内部構造を隠したまま、それぞれの要素にアクセスさせるためのパターン

  • オブジェクトに対する反復操作をおこなうための統一APIを提供するパターン

Iterator パターンのメリット

  • 利用者に、「どの様な構造を持つリストなのか」を意識させないようにできます。

実装例

<?php

class Employee
{
    private $name;
    private $age;
    private $job;

    public function __construct($name, $age, $job)
    {
        $this->name = $name;
        $this->age = $age;
        $this->job = $job;
    }

    public function getName()
    {
        return $this->name;
    }

    public function getAge()
    {
        return $this->age;
    }

    public function getJob()
    {
        return $this->job;
    }
}

class Employees implements IteratorAggregate
{
    private $employees;
    public function __construct()
    {
        $this->employees = new ArrayObject();
    }

    public function add(Employee $employee)
    {
        $this->employees[] = $employee;
    }

    public function getIterator()
    {
        return $this->employees->getIterator();
    }
}

$employees = new Employees();
$employees->add(new Employee('SMITH', 32, 'CLERK'));
$employees->add(new Employee('ALLEN', 26, 'SALESMAN'));
$employees->add(new Employee('MARTIN', 50, 'SALESMAN'));
$employees->add(new Employee('CLARK', 45, 'MANAGER'));
$employees->add(new Employee('KING', 58, 'PRESIDENT'));

$iterator = $employees->getIterator();

while  ($iterator->valid()) {
    $employee = $iterator->current();

    printf(
        "%s (%d, %s)\n",
        $employee->getName(),
        $employee->getAge(),
        $employee->getJob()
    );

    $iterator->next();
}

参考

PHP でデザインパターン (Strategy)

2018-10-14

Strategy パターンとは

Strategyパターンでは、アルゴリズムの部分を他の部分と意識的に分離します。

Strategy パターンのメリット

  • 処理毎にまとめることができる
  • 異なる処理を選択するための条件文がなくなる
  • 異なる処理を動的に切り替えることができる

実装例

<?php

abstract class ReadItemDataStrategy
{
    private $filename;
    public function __construct($filename)
    {
        $this->filename = $filename;
    }

    public function getData()
    {
        return $this->readData($this->getFileName());
    }

    public function getFileName()
    {
        return $this->filename;
    }

    protected abstract function readData($filename);
}

class ReadFixedLengthDataStrategy extends ReadItemDataStrategy
{
    protected function readData($filename)
    {
        // MEMO: 実際は読み込みの処理を実装する
        $data = [];
        $data[] = self::class;
        $data[] = sprintf('このファイルを読み込みます: %s', $filename);

        return $data;
    }
}

class ReadTabSeparatedDataStrategy extends ReadItemDataStrategy
{
    protected function readData($filename)
    {
        // MEMO: 実際は読み込みの処理を実装する
        $data = [];
        $data[] = self::class;
        $data[] = sprintf('このファイルを読み込みます: %s', $filename);

        return $data;
    }
}

class ItemDataContext
{
    private $strategy;

    public function __construct(ReadItemDataStrategy $strategy)
    {
        $this->strategy = $strategy;
    }

    public function getItemData()
    {
        return $this->strategy->getData();
    }
}

$strategy1 = new ReadFixedLengthDataStrategy('dummy1.txt');
$context1 = new ItemDataContext($strategy1);
var_dump($context1->getItemData());

echo "\n";

$strategy2 = new ReadTabSeparatedDataStrategy('dummy2.txt');
$context2 = new ItemDataContext($strategy2);
var_dump($context2->getItemData());

参考

ブログシステムを Github Pages で構築する

2018-10-13

目的

ブログシステムを Github Pages を使い構築しました。

メモがてら、概要と運用してみた感想について書きます。

(具体的な構築手順は、この記事では書きません)

システム構成

シンプルな構成です。

図1.

システム構成-Github Pages

デプロイについて

作業用PC から Jekyll で作成したブログを Github へ Push します。

運用してみて

実際に運用してみました。 作業用 PC (ローカル)でビルドしなくて良いです。

※ 表示確認でビルドすることにはなりますが。

所感

よかったこと

ホスティングするサーバーを借りなく良いので、気軽に始められます。

よくなかったこと

Jekyll のプラグインがセキュリティの観点から Github Pages で動かないものがありました。

作業用 PC (ローカル)でビルド済みのソースコードもバージョン管理すれば、できると思います。

Laravel のサービスプロバイダ、サービスコンテナについて

2018-10-09

目的

Laravel を利用するとき、サービスプロバイダ、サービスコンテナについて、あまり理解していなかったので調べてみました

サービスプロバイダとは

サービスプロバイダは、Laravelアプリケーション全体の起動処理における、初めの心臓部です。

インスタンス化方法を登録します

サービスコンテナとは

Laravelのサービスコンテナは、クラス間の依存を管理する強力な管理ツールです。

インスタンス化の方法が定義されます

ほとんどのサービスコンテナの結合は、サービスプロバイダで行います

DI コンテナみたいなものです

ここで管理することにより、呼び出し元が多数あった場合も

ここを修正すれば良くなりました。

参考

JavaScript の shift と unshift を試す

2018-10-08

目的

JavaScriptのshiftとunshiftの挙動を試しました。

配列の操作(shift unshift)

var numbers = ["one", "two", "three"];
console.log(numbers);

var shifted = numbers.shift(); // 配列の最初の要素を取り除く
console.log(numbers);
console.log(shifted);

numbers.unshift("four"); // 配列の先頭に追加
console.log(numbers);

結果

["one", "two", "three"]
["two", "three"]
one
["four", "two", "three"]

参考URL

Google Chrome 拡張機能のソースコードを見る方法

2018-10-08

目的

Google Chrome 拡張機能のソースコードを解析します

やってみる

拡張機能が保存されているディレクトリ

Mac で保存されている場所

~/Library/Application Support/Google/Chrome/Default/Extensions

拡張機能の ID を調べる

Chrome Web Store で調べます

調べたい拡張機能のページに遷移して URL を確認します

https://chrome.google.com/webstore/detail/adblock/xxxxx?hl=ja

上記の xxxxx の部分が 拡張機能のパスです

参考