2020/02/08

DIについては、DI(依存性注入) を参照

DIコンテナは、DIのインスタンス生成を、別のファイルでコンテナ化して解決しようという設計パターンです。

共通クラスを用意

まず、共通で使う Animalクラスを用意します。
手っ取り早くファイル分割せず Animal.php にクラス(Dog、Cat)を記述しました。


interface Animal {
    public function bow();
}

class Dog implements Animal {
    public function bow() {
        echo 'wan! wan!'.PHP_EOL;
    }
}

class Cat implements Animal {
    public function bow() {
        echo 'nya-! nya-!'.PHP_EOL;
    }
}

DIでない例

下記のサンプルはコンストラクタ内で Dog を生成して鳴きます。


class AnimalConsole {
    protected $dog;

    public function __construct() {
        $this->dog = new Dog();
    }

    public function bow() {
        $this->dog->bow();
    }
}

$animal_console = new AnimalConsole();
$animal_console->bow();

この場合、コンストラクタで new Dog() するため、Dogが実装できるまで AnimalConsole が実装できません。

DI(?)の場合

コンストラクタの引数に、Dog、Cat インスタンスを注入します(コンストラクタインジェクション)
他の記事をみているとこれで「DI」となってますが、まだ Dog に依存しているため Cat に修正したい場合に手間がかかります。


require_once 'Animal.php';

class AnimalConsole {
    protected $dog;

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

    public function bow() {
        $this->dog->bow();
    }
}

$animal_console = new AnimalConsole(new Dog());
$animal_console->bow();

インターフェイス(モック)を引数にしてみる

今度は Dog、Cat 両方扱えるように Amimal を引数とします。


require_once 'Animal.php';

class AnimalConsole {
    protected $animal;

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

    public function bow() {
        $this->animal->bow();
    }
}

$animal_console1 = new AnimalConsole(new Dog());
$animal_console1->bow();

$animal_console2 = new AnimalConsole(new Cat());
$animal_console2->bow();

これで、Dog、Cat どちらでも注入できるようになりました。

pimpleでDIコンテナを作成する

インスタンスを直接渡すのではなく、コンテナ(箱)内でインスタンスを作成して処理するのが、DIコンテナです。

今回は、composerのContainerライブラリ「pimple」を利用しています。

Pimpleインストール


$ composer require pimple/pimple ~3.0

PimpleによるDIコンテナ

下記の場合、Dog、Cat のインスタンスをコンテナ化しています。

また、$container['animal'] では、インスタンスを簡単に切り替えることができます。


require_once 'Animal.php';
require_once __DIR__.'/../vendor/autoload.php';

use Pimple\Container;

class AnimalConsole {
    protected $animal;

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

    public function bow() {
        $this->animal->bow();
    }
}

$container = new Container();

$container['dog'] = function($c) {
    return new Dog();
};

$container['cat'] = function($c) {
    return new Cat();
};

$container['animal'] = function($c) {
    return $c['dog'];
};

$container['animalConsole'] = function ($c) {
    return new AnimalConsole($c['animal']);
};

$container['animalConsole']->bow();

Container の部分はファイル分離する必要はあります。

  2020/02/06

freee API は 開発者向けにOSS として公式公開されています。

https://developer.freee.co.jp/

 

ここでは、リファレンスを利用して認可コード・アクセストークン・API確認をしてみる。

実際の開発は各言語やSDKを使ってコーディングが必要だが、PHPに関しては、freee SDKを Laravel で使ってみる でやってみた。

開発者アカウント登録と環境・アプリ作成

まず、freeeアカウントを作成(一般ユーザアカウント)する

開発用テスト環境作成

次に開発ユーザでログインし、開発用テスト環境の作成する。

テスト環境の事業所を選択

アプリ追加

 アプリ追加画面でアプリを追加すると、Client ID, Client secret が発行される

作成したアプリは、アプリ管理 で管理する

freee API のドキュメント

API を試してみる

認可コード発行

「Webアプリ認証用URL」でブラウザでアクセスし、許可すると「認可コード」が発行される
※アクセストークンではない

アクセストークン発行

https://accounts.secure.freee.co.jp/public_api/authorize?client_id={client_id}&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&response_type=token 

上記のURLに freee アプリで発行された Client ID を入れてブラウザでリクエストする

事業所取得

https://developer.freee.co.jp/docs/accounting/reference#/Companies/get_companies

鍵マークをクリック

value に アクセストークンを入力して [Authorize]し、成功したら[Close]

[Try it out] をクリックし [Execute] するとAPIが実行される

事業所一覧取得API(companies)の場合

curl


curl -X GET "https://api.freee.co.jp/api/1/companies" -H "accept: application/json" -H "Authorization: Bearer {Client ID}"

Request Body


https://api.freee.co.jp/api/1/companies

Request URI


{
  "companies": [
    {
      "id": xxxxxxx,
      "name": "",
      "name_kana": "",
      "display_name": "個人事業主名",
      "role": "admin"
    },
    {
      "id": xxxxxxx,
      "name": null,
      "name_kana": null,
      "display_name": "個人事業主スタータープラン: 開発用テスト環境",
      "role": "admin"
    }
  ]
}

  2020/01/12

Composer 公式のインストール

$ php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
$ php -r "if (hash_file('sha384', 'composer-setup.php') === 'baf1608c33254d00611ac1705c1d9958c817a1a33bce370c0595974b342601bd80b92a3f46067da89e3b06bff421f182') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
$ php composer-setup.php
$ php -r "unlink('composer-setup.php');"
$ sudo mv composer.phar /usr/local/bin/composer

getcomposer.org のPHPインストーラを利用する

ComposerインストールようのPHPファイル https://getcomposer.org/installer を利用して /usr/local/bin/ にcomposer をインストール
$ curl -s https://getcomposer.org/installer | php && sudo mv -v composer.phar /usr/local/bin/composer

Composer バージョン確認

$ composer --version
Composer version 1.9.1 2019-11-01 17:20:17

Composer アップデート

$ composer self-update

  2019/12/30

DIとは

DI(Dependency injection) は依存性の注入の意味です。

ここで言う「依存性」は、オブジェクト思考でいうと大まかに「クラスファイル」と考えて良いかと。

そしてそのクラスが特定の定数、変数、インスタンスに依存しまい、単体テストに支障がでている状態です。

class Dog {
    public function isBow() {
        $person = new Person();
        return ($person->action() ==  'walk');
    }
}
class TestDog {
    public function testBow() {
        $dog = new Dog();
        $this->assertTrue($dog->isBow());
    }
}

上記だと、Dogクラス内にPersonクラスに依存してしまってます。 「$person->action() == 'walk'」の実装が変わってしまうと、assertTrue() した結果は、Personクラスが変更があった場合に変わってしまいます。

解決方法としては、Dogクラスの動作させるメソッドでインスタンスを作成せずに、コンストラクタやセッターに、Personを入れて(注入)して解決します。

class Dog {
    protected $person;
   
    public function __construct(Person $person) {
        $this->person = $person;
    }

    public function isBow() {
        return ($this->person->action() == 'walk');
    }
}
class TestDog {
    public function testBow() {
        $person = new Person();
        $person->expects($this->any())
            ->method('action')
            ->will($this->returnValue('walk'));
        $dog = new Dog($person);
        $this->assertTrue($dog->isBow());
    }
}

  2019/05/15
UFJ が API を虎視眈々と開発していた。 カブドットコムのAPIも使えたりと結構楽しそう、というか近々実用化されそうな予感がします。 カブドットコムのAPI(kabu.com API)は本番環境で利用できるとのことだが、法人契約が必要なのと当然ながら審査が必要。

開発用API登録

UFJ API

API種別

2019/05/15現在、個人口座、法人口座、振込申請、総合振込申請、給与賞与振込申請、特別徴収地方税のAPIが用意されている。 UFJ API

API Client Secretの発行

当然ながらAPIを利用するには、Client Secret の発行が必要となる。 UFJ API

APIリファレンス

各サービス毎にリファレンスは用意されている。 cURL,Ruby,Python,PHP,Java,Node,Go,Swift のサンプルが記載されており、結構本気度が伺えられる。 また、レスポンスは基本 json のようだ。 UFJ API ただ本番利用の場合は、金融業界なので審査が厳しいと予想される。

ライブラリ(PHP)

使いやすいように、ざっとクラスライブラリを作成してみた。 ufj_api (2019/05/15現在アカウント情報取得のみ) また、検証用データが用意されていて、Account ID一覧は以下の通り
001001110001 002001110002 325001110003 135011110005 118011110008 329011110009 002021110013 002022220003 325022220004 909022220013 002022220014 002023330003 325023330004 480023330005 777023330008 118023330009 427383330012 909383330013 002383330014 002283330016

実行結果

$ php get_account.php 002023330003 {"branchNo":"002","branchName":"丸の内","accountTypeCode":"02","accountTypeDetailCode":"00099","accountTypeName":"定期","accountNo":"3330003","accountName":null,"accountNameKana":null,"balance":100000,"withdrawableAmount":null,"currencyCode":"JPY","foreignCurrencyBalance":null,"yenEquivalent":null,"exchangeRate":null,"totalMarketValue":null,"totalUnrealizedProfitAndLoss":null,"mutualFundAccountType":null,"fundBaseDate":null}

  2019/04/29
PHP7.3 で break と continue の取り扱いが変更になった影響で、composer install がエラーになる場合、
  • PHP7.2にさげる
  • composer のバージョンをあげる
    $ composer global require "laravel/installer"
    Changed current directory to /home/yoo/.config/composer
    Using version ^2.0 for laravel/installer
    ./composer.json has been created
    Loading composer repositories with package information
    Updating dependencies (including require-dev)
    
    Installation failed, deleting ./composer.json.
                                                                                               
      [ErrorException]                                                                         
      "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"?  
                                                                                               
    require [--dev] [--prefer-source] [--prefer-dist] [--no-progress] [--no-update] [--no-scripts] [--update-no-dev] [--update-with-dependencies] [--ignore-platform-reqs] [--prefer-stable] [--prefer-lowest] [--sort-packages] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--] []...
    
    特に初期設定で composer のバージョンが低い場合は注意が必要 (composer self-udpate がないなど) composer installができなくなった時の解決法(PHP7.3)

    PHP7.2 に変更

    $ sudo update-alternatives --config php
      選択肢    パス           優先度  状態
    ------------------------------------------------------------
    *0            /usr/bin/php7.3   73        自動モード
      1            /usr/bin/php5     50        手動モード
      2            /usr/bin/php7.0   70        手動モード
      3            /usr/bin/php7.2   72        手動モード
      4            /usr/bin/php7.3   73        手動モード
    

    composerの再インストール(self-udpateなど利用できない場合)

    composer-setup.php をダウンロード・実行する
    $ curl -sS https://getcomposer.org/installer | php
    $ sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer
    $ composer -V
    Composer version 1.8.5 2019-04-09 17:46:47
    
    2019/12/09追記 一発でインストールする
    $ curl -s https://getcomposer.org/installer | php && sudo mv -v composer.phar /usr/local/bin/composer
    

  2019/04/25
PHPの配列は他の言語と比べて若干癖がある。 インデックスが 型が整数か文字列とか連番でなくてもよいとかゆるいので、ある意味柔軟なデータを生成する事もできる。 (ここら辺は言語思想) PHP配列の結合は「array_merge() 」が一般的かも知れないが、演算子でも計算できる。 ただし、インデックスによって結果が異なるので注意が必要。
  • インデックスが同じ、異なる
  • 値が同じ、異なる
の組み合わせで考察してみる。 事前に結合するサンプルデータを作成しておく(例では10個ずつ)。
    function generateValues($count, $prefix = 'test', $from_index = 1)
    {
        for ($i = $from_index; $i <= $count + $from_index; $i++) $values[$i] = "{$prefix}{$i}";
        return $values;
    }
$values1 = 
array (
  0 => 'test0',
  1 => 'test1',
  2 => 'test2',
  3 => 'test3',
  4 => 'test4',
  5 => 'test5',
  6 => 'test6',
  7 => 'test7',
  8 => 'test8',
  9 => 'test9',
)
$values2 = 
array (
  0 => 'test0',
  1 => 'test1',
  2 => 'test2',
  3 => 'test3',
  4 => 'test4',
  5 => 'test5',
  6 => 'test6',
  7 => 'test7',
  8 => 'test8',
  9 => 'test9',
)

$values1 + $values2 の結合(インデックス同じ、値同じ)

$values1 + $values2 を演算子「+」で結合してみる。
//values1 + values2
$values1 = $array_merge->generateValues(10);
$values2 = $array_merge->generateValues(10);
$values = $values1 + $values2;
$values1 + $values2 = 
array (
  0 => 'test0',
  1 => 'test1',
  2 => 'test2',
  3 => 'test3',
  4 => 'test4',
  5 => 'test5',
  6 => 'test6',
  7 => 'test7',
  8 => 'test8',
  9 => 'test9',
)
インデックスが同じだと結合できない。 またどちらの配列が採用されているかわからないので、値の違う配列を作成して調べる。

$values1 + $values2 の結合(インデックス同じ、値異なる)

//values1 + values2
$values1 = $array_merge->generateValues(10, 'red');
$values2 = $array_merge->generateValues(10, 'blue');
$values = $values1 + $values2;
$values1 = 
array (
  0 => 'red0',
  1 => 'red1',
  2 => 'red2',
  3 => 'red3',
  4 => 'red4',
  5 => 'red5',
  6 => 'red6',
  7 => 'red7',
  8 => 'red8',
  9 => 'red9',
)
$values2 = 
array (
  0 => 'blue0',
  1 => 'blue1',
  2 => 'blue2',
  3 => 'blue3',
  4 => 'blue4',
  5 => 'blue5',
  6 => 'blue6',
  7 => 'blue7',
  8 => 'blue8',
  9 => 'blue9',
)
$values1 + $values2 = 
array (
  0 => 'red0',
  1 => 'red1',
  2 => 'red2',
  3 => 'red3',
  4 => 'red4',
  5 => 'red5',
  6 => 'red6',
  7 => 'red7',
  8 => 'red8',
  9 => 'red9',
)
上書きされずに最初の配列が採用されていることがわかる。

array_merge($values1, $values2)での結合(インデックス同じ、値同じ)

同じ内容の配列を array_merge() するとインデックスが振り直された配列を返す。
$values = array_merge($values1, $values2);
array (
  0 => 'test0',
  1 => 'test1',
  2 => 'test2',
  3 => 'test3',
  4 => 'test4',
  5 => 'test5',
  6 => 'test6',
  7 => 'test7',
  8 => 'test8',
  9 => 'test9',
  10 => 'test0',
  11 => 'test1',
  12 => 'test2',
  13 => 'test3',
  14 => 'test4',
  15 => 'test5',
  16 => 'test6',
  17 => 'test7',
  18 => 'test8',
  19 => 'test9',
)
今度は、インデックスの異なる配列で試してみる。 配列の作成は以下で作成
    function generateValuesWithIndex($count, $prefix = 'test')
    {
        for ($i = 0; $i < $count; $i++) {
            $values[$this->index++] = "{$prefix}{$i}";
        }
        return $values;
    }
$values1 = 
array (
  0 => 'test0',
  1 => 'test1',
  2 => 'test2',
  3 => 'test3',
  4 => 'test4',
  5 => 'test5',
  6 => 'test6',
  7 => 'test7',
  8 => 'test8',
  9 => 'test9',
)
$values2 = 
array (
  20 => 'test0',
  21 => 'test1',
  22 => 'test2',
  23 => 'test3',
  24 => 'test4',
  25 => 'test5',
  26 => 'test6',
  27 => 'test7',
  28 => 'test8',
  29 => 'test9',
)

$values1 + $values2 の結合(インデックス異なる、値同じ)

$values = $values1 + $values2;
$values1 + $values2 = 
array (
  0 => 'test0',
  1 => 'test1',
  2 => 'test2',
  3 => 'test3',
  4 => 'test4',
  5 => 'test5',
  6 => 'test6',
  7 => 'test7',
  8 => 'test8',
  9 => 'test9',
  20 => 'test0',
  21 => 'test1',
  22 => 'test2',
  23 => 'test3',
  24 => 'test4',
  25 => 'test5',
  26 => 'test6',
  27 => 'test7',
  28 => 'test8',
  29 => 'test9',
)
インデックスを保持したまま結合できる。

array_merge($values1, $values2)での結合(インデックス異なる、値同じ)

$values = array_merge($values1, $values2);
array (
  0 => 'test0',
  1 => 'test1',
  2 => 'test2',
  3 => 'test3',
  4 => 'test4',
  5 => 'test5',
  6 => 'test6',
  7 => 'test7',
  8 => 'test8',
  9 => 'test9',
  10 => 'test0',
  11 => 'test1',
  12 => 'test2',
  13 => 'test3',
  14 => 'test4',
  15 => 'test5',
  16 => 'test6',
  17 => 'test7',
  18 => 'test8',
  19 => 'test9',
)
インデックスが振り直されて結合される。

  2018/03/07
PHP7.1 で JpGraph4.2.0 を利用すると gd_image.inc.php でエラーになる。
function SetAntiAliasing($aFlg=true) {
        $this->use_anti_aliasing = $aFlg;
        if( function_exists('imageantialias') ) {
            imageantialias($this->img,$aFlg);
        }
        else {
            JpGraphError::RaiseL(25128);//('The function imageantialias() is not available in your PHP installation. Use the GD version that comes with PHP and not the standalone version.')
        }
    }
imageantialias() が利用できないのが原因 PHP : imageantialias()
7.2.0 imageantialias() が常に使えるようになりました。 これまでのバージョンでは、PHP にバンドルされている GD ライブラリでコンパイルした場合にしか使えませんでした。
Debian のPHP7.1パッケージではダメで、PHP7.2 では動作した。

  2017/06/08
get_defined_constants() そのままだと全ての define値を取得される。 引数に「true」指定すると、連想配列の「user」にユーザ指定した define値を取得できる。
        $defined_constants = get_defined_constants(true);
        $this->defined_constants = $defined_constants['user'];

  2015/03/26
# echo deb http://dl.hhvm.com/ubuntu saucy main | tee /etc/apt/sources.list.d/hhvm.list # wget -O - http://dl.hhvm.com/conf/hhvm.gpg.key | apt-key add -
<< 最初 < 前ページ 次ページ > 最後 >>