76
74

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

自作Composerのパッケージの基本的な構成

Last updated at Posted at 2017-03-12

●はじめに

以下の記事は当時の自分の検索スキルが足らず、該当する内容を見つけられず仕方なく自分で考察・実装した時のメモです。

コメントで教えて頂いたhttps://github.com/php-pds/skeletonの方がより洗練されて美しいので、こちらを参考にしてもらった方が良いと思います。

以上ご了承の上で敢えて読みたい方は以下から本編です。

●概要

経緯として複数のWebアプリケーションで使用するモデルとビジネスロジックや、コマンドラインで使用するモジュールをコピペで再利用していた。
当然、追加機能の開発やらバグ対応やら運用がツライ → 爆死。

本当にありがとうございました。

これじゃーイカンなと、Composerパッケージとして開発・運用する必要があるなと痛感した次第であります。
「ではどうするか?」となった時に調査して考えた内容で、ある程度土台(テンプレートともいう)は共通化する必要があるのでまとめた。

要するにcomposerでパッケージ作る時の土台部分の話。

●目的

土台を共通化することで

  • 開発効率を上げる
  • 属人化しない。(未来の自分に優しく)
  • 再利用しやすい
  • 開発・バグ対応が簡単

●方針

個人・自社のみの使用を想定。 ← クローズドな環境で使用するの意味。
再利用する単位(モジュール)でパッケージにする。
基本的にはWebアプリケーションでは無い。

  • 複数のWebアプリケーションで利用するモデルやビジネスロジック
  • コマンドラインで使用する

などなど

Webフレームワークを使用する場合はそれに合わせる。ほとんどのWebフレームワークには以下の構成・運用に大体なっていると思うが。

■使用パッケージ

Composerが親の仇っていう人は帰ってどうぞ。
それ以外の人はComposerを使ってパッケージを入れる。最低限これだけは入れとけってヤツ。

  • monolog
  • .env
  • phpunit
  • psysh

■基本的な運用

必要なパッケージをcomposerで追加。
 →車輪の再発明はイヤだ。
composerの自作パッケージとして再利用出来るようにする。
 →自分が作ったからと言ってもコピペはツライ。
当然gitも使用する。
 →composerのパッケージとして利用出来るように、gitのtagとcomposer.jsonのバージョンを合わせる

●パッケージ名の命名規則

全て小文字でダッシュを挟む。

my-package

Composer ドキュメント日本語訳 → 全てのプロジェクトはパッケージである → 注意

今後この記事では説明の為にmy-packageをパッケージ名として作る。

●ディレクトリ構成とファイル

いろんなパッケージを参考にしている。

■最低限必要だよねっていうディレクトリ

  • logs:ログファイルを置き場
  • src/MyPackage/Exception:ソースファル置き場
  • tests:テストファイル置き場

「MyPackage」のところは、作るパッケージ名合わせて変える。

■必要に応じて入れればいいんじゃないかっていうディレクトリ

  • docs:readme.mdで収まり切らない場合の説明を入れる
  • example:readme.mdで収まり切らない場合の使用例
  • bin:バイナリファイル

■諸々の設定ファイルとか

  • .gitignore:2箇所。git無視ファイル
  • composer.json:パッケージの依存性とかのファイル
  • phpunit.xml:phpunit設定ファイル
  • psysh.php:psyshの実行を簡単にするファイル
  • readme.md:目的と使い方ぐらいは書きたい

■composerが作成するファイル

  • composer.lock:composer installとかを実行すると自動で作られる
  • vendor/autoload.php:クラスのオートロードファイル
  • vendor/bin/phpunit:phpunitバイナリファイル
  • vendor/bin/psysh:psyshバイナリファイル

■最終的な構成例

my-package
├── .gitignore
├── bin
├── composer.json
├── composer.lock
├── docs
├── example
├── logs
│   └── .gitignore
├── phpunit.xml
├── psysh.php
├── readme.md
├── src
│   └── MyPackage
│       └── Exception
├── tests
└── vendor
    ├── autoload.php
    ├── bin
    │   ├── php-parse -> ../nikic/php-parser/bin/php-parse
    │   ├── phpunit -> ../phpunit/phpunit/phpunit
    │   └── psysh -> ../psy/psysh/bin/psysh
    ├── composer
    ...

●作り方

パッケージのvendor(所属)をきめておく。
個人ならgithubのアカウント。会社なら会社名とか。

composerをいれる。ここはググればいくらでも検索が出るので省く

■composer.jsonの作成

$ mkdir my-package
$ cd ./my-package/
$ composer init


  Welcome to the Composer config generator



This command will guide you through creating your composer.json config.

Package name (<vendor>/<name>) [busyoumono/my-package]: busyoumono99/my-package
Description []:
Author [busyoumono99 <xxxx@xxxxxx.com>, n to skip]
Minimum Stability []: stable
Package Type (e.g. library, project, metapackage, composer-plugin) []: library
License []: MIT

Define your dependencies.

Would you like to define your dependencies (require) interactively [yes]?
Search for a package:
Would you like to define your dev dependencies (require-dev) interactively [yes]?
Search for a package:

{
    "name": "busyoumono99/my-package",
    "type": "library",
    "license": "MIT",
    "minimum-stability": "stable",
    "require": {}
}

Do you confirm generation [yes]?
$ composer require vlucas/phpdotenv
$ composer require monolog/monolog
$ composer require phpunit/phpunit --dev
$ composer require psy/psysh:@stable --dev

■各ディレクトリの作成

$ mkdir -p src/MyPackage/Exception
$ mkdir logs
$ mkdir tests
$ mkdir docs
$ mkdir example
$ mkdir bin

■オートロード

composer.jsonにオートロードの設定を追加する。

"autoload": {
    "psr-4": {
        "busyoumono99\\MyPackage\\": "src/MyPackage/"
    }
},

autoloadの設定を反映させる

$ composer dump-autoload

 

■.envを作成

$ vi .env

TEST_NAME=hoge

■gitignore

vi .gitignore

/vendor
.env

vi logs/.gitignore

*
!.gitignore

■psysh用のシェルスクリプト作成

デバッグ時にphpを対話方式で実行する。autoload等毎回設定するのは面倒なので、決まりきった処理を書いて楽をする。

$ vi psysh.php
#!/usr/bin/env php
<?php
// ↓名前空間を利用するプロジェクトでは記述しておく
namespace busyoumono99\MyPackage;

// Composerのオートローダーを読み込む
require_once __DIR__ . '/vendor/autoload.php';
// ほかに初期化用のPHPファイルがあれば読み込んでおく
// require_once …

// .envの読込。.envが必要ない、使用しない場合はコメントアウトする
$dotenv = new \Dotenv\Dotenv(__DIR__.'/');
$dotenv->load();

echo __NAMESPACE__ . " shell\n";

$sh = new \Psy\Shell();

// シェル起動直後にプロジェクトのnamespaceを設定する
// 名前空間を利用しないプロジェクトでは↓の行は不要
$sh->addCode(sprintf("namespace %s;", __NAMESPACE__));

$sh->run();

// 終了時に表示するメッセージ
echo "Bye.\n";
# 実行権限を追加する
$ chmod +x ./psysh.php

■phpunit.xml

phpunitの設定ファイル。

<?xml version="1.0" encoding="utf-8" ?>
<phpunit colors="true" bootstrap="vendor/autoload.php">
    <testsuites>
        <testsuite name="All tests">
            <directory>tests/</directory>
        </testsuite>
    </testsuites>
</phpunit>

bootstrapは基本的にautoloadしか設定しないのでこうした。

もしbootstrapに.envの読込やタイムゾーンの設定が必要になったらtests直下にbootstrap.phpを作って、その中でゴニョゴニョする。
それに合わせてbootstrap="tests/bootstrap.php"に変更する。

●使い方(開発時)

■monolog

ログの簡単な使い方。

<?php

namespace busyoumono99\MyPackage;

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\RotatingFileHandler;

class LogSample
{

    public static function write($message){
      $log = new Logger('my-package');
      // ログのパスを設定する
      $log_path = __DIR__. '/../../logs/test.log';
      //ログレベルをDEBUG(最も低い)に設定
      $handler = new StreamHandler($log_path,Logger::DEBUG);
      $log->pushHandler($handler);
      // ログローテーションのハンドラーを使う
      $rotating_handler = new RotatingFileHandler($log_path, 30, Logger::DEBUG, true);
      $log->pushHandler($rotating_handler);

      // 書き込む
      return $log->addDebug($message);
    }
}

解説

  • Loggerクラスと必要なハンドラークラスを読み込む。
  • ハンドラーは複数設定出来る。
  • ハンドラーを複数設定した場合は同時に書き込む。
  • ログレベルの設定で開発・本番等の切り替えが出来る。

他にも色々と機能等があるので詳細は別途ググると良い。以下大きいところ。

  • ハンドラーにはファイルの書き込み以外に、DBに書き込み、メール送信、Slack等の外部サービスと連携とかがある。
  • フォーマットの機能もある

■.env

利用前の設定。bootstrap.php的なライブラリのセットアップ時に読込処理をしておく。

// Composerのオートローダーを読み込む
require_once __DIR__ . '/vendor/autoload.php';
// .envの読込。
$dotenv = new \Dotenv\Dotenv(__DIR__.'/');
$dotenv->load();

実際に値を取得する。

<?php

namespace busyoumono99\MyPackage;

class EnvSample
{
    /**
     * .envの使用例
     * @return string
     */
    public static function getTestName()
    {
        return getenv('TEST_NAME');
    }

}

■phpunit

○クラス

例えば四則演算のクラス

src/MyPackage/Arithmetic.php

<?php

namespace busyoumono99\MyPackage;


class Arithmetic
{
    /**
     * 足し算
     */
    public function add($x, $y) {
        return($x + $y);
    }

    /**
     * 引き算
     */
    public function subtract($x, $y) {
        return($x - $y);
    }

    /**
     * 掛け算
     */
    public function multiply($x, $y) {
        return($x * $y);
    }

    /**
     * 割り算
     */
    public function divide($x, $y) {
        return($x / $y);
    }
}

○テストケース

tests/ArithmeticTest.php

<?php
use PHPUnit\Framework\TestCase;
use busyoumono99\MyPackage\Arithmetic;

class ArithmeticTest extends TestCase
{
  /**
     * @var Arithmetic
     */
    protected $object;

    /**
     * setUpは各テストメソッドが実行される前に実行する
     */
    protected function setUp() {
        // テストするオブジェクトを生成する
        $this->object = new Arithmetic();
    }

    /**
     * 足し算関数の検証
     * @test
     */
    public function 3足す5は8() {
        $this->assertEquals(8, $this->object->add(3, 5));
    }

    /**
     * @test
     */
    public function 15足す30は45() {
        $this->assertEquals(45, $this->object->add(15, 30));
    }

    /**
     * 引き算関数の検証
     * @test
     */
    public function 10引く3は7() {
        $this->assertEquals(7, $this->object->subtract(10, 3));
    }

    /**
     * @test
     */
    public function 3引く9はー6() {
        $this->assertEquals(-6, $this->object->subtract(3, 9));
    }

    /**
     * 掛け算関数の検証
     * @test
     */
    public function 4かける6は24() {
        $this->assertEquals(24, $this->object->multiply(4, 6));
    }

    /**
     * @test
     */
    public function 4かけるー5はー20() {
        $this->assertEquals(-20, $this->object->multiply(4, -5));
    }

    /**
     * 割り算関数の検証
     */
    public function testDivide() {
        // 引数に6,2を渡すと3が返ってくることを確認する
        $this->assertEquals(3, $this->object->divide(6, 2));
        // 引数に6,6を渡すと1が返ってくることを確認する
        $this->assertEquals(1, $this->object->divide(6, 6));
    }
}
  • setUpに各テスト前に実行する共通処理を書く
  • ドキュメントに@testが含まれているとテストする
  • メソッドのプレフィックスがtestならテストする
  • assertEqualsは値が等しい事をテストする。
  • assertEqualsで結構いける
  • 他にもアサートはある。
  • 時間がかかる時は@groupを検討する

○テスト実行

ターミナルで以下実行

$ ./vendor/bin/phpunit
PHPUnit 6.0.8 by Sebastian Bergmann and contributors.

.......                                                             7 / 7 (100%)

Time: 188 ms, Memory: 4.00MB

OK (7 tests, 8 assertions)

■psysh

psyshでデバッグ実行する

○シェルスクリプトを使用する

$ cd /path/to/my-package
$ ./psysh.php
busyoumono99\MyPackage shell
Psy Shell v0.8.2 (PHP 7.0.15 — cli) by Justin Hileman
>>> $ar = new Arithmetic()
=> busyoumono99\MyPackage\Arithmetic {#162}
>>> show $ar
  >  6| class Arithmetic
     7| {
     8|     /**
     9|      * 足し算
    10|      */
    11|     public function add($x, $y) {
    12|         // eval(\Psy\sh());
    13|         return($x + $y);
    14|     }
    15|
    16|     /**
    17|      * 引き算
    18|      */
    19|     public function subtract($x, $y) {
    20|         return($x - $y);
    21|     }
    22|
    23|     /**
    24|      * 掛け算
    25|      */
    26|     public function multiply($x, $y) {
    27|         return($x * $y);
    28|     }
    29|
    30|     /**
    31|      * 割り算
    32|      */
    33|     public function divide($x, $y) {
    34|         return($x / $y);
    35|     }
    36| }

>>> ls $ar
Class Methods: add, divide, multiply, subtract
>>> $ar->add(5,9)
=> 14
>>> dump $ar
busyoumono99\MyPackage\Arithmetic {#162}
>>> q
Exit:  Goodbye.
Bye.

○簡単に試す時とか

$ ./vendor/bin/psysh
Psy Shell v0.8.2 (PHP 7.0.15 — cli) by Justin Hileman
>>> $a = ["hoge"=>"piyo", "fuga"=>"poyo"]
=> [
     "hoge" => "piyo",
     "fuga" => "poyo",
   ]
>>> json_encode($a)
=> "{"hoge":"piyo","fuga":"poyo"}"
>>> q
Exit:  Goodbye.

○ブレイクポイントとして利用

以下をブレイクしたい箇所に追加。例えば足し算メソッドに仕込む。

eval(\Psy\sh());
...
    /**
     * 足し算
     */
    public function add($x, $y) {
        eval(\Psy\sh());
        return($x + $y);
    }
...

シェルスクリプトで起動してブレイクポイントを発生させる

$ ./psysh.php
busyoumono99\MyPackage shell
Psy Shell v0.8.2 (PHP 7.0.15 — cli) by Justin Hileman
>>> $ar = new Arithmetic()
=> busyoumono99\MyPackage\Arithmetic {#162}
>>> $ar->add(5, 13)

Psy Shell v0.8.2 (PHP 7.0.15 — cli) by Justin Hileman  ← ここで2重にpsyshが実行されている。
>>> ls
Variables: $this, $x, $y
>>> dump $x
5
>>> dump $y
13
>>> ls $this
Class Methods: add, divide, multiply, subtract
>>> dump $this
busyoumono99\MyPackage\Arithmetic {#162}
>>> q
Exit:  Goodbye.
=> 18
>>> q
Exit:  Goodbye.
Bye.

./psysh.phpで無くても$ php -f index.phpやブラウザアクセス等でも良い。eval(\Psy\sh());の箇所まで処理が進めばターミナルが起動してpsyshが開始される。ただ、面倒なので./psysh.phpがオススメ

○主に使うコマンド

自分が現在の所、主に使うコマンド3つ。

* ls : 現在有効な変数の一覧
* ls $obj : オブジェクト変数のプロパティ、メソッドとか
* dump $var : 変数の中身を表示
* q : psyshの終了

■git

gitは通常にコミット。バージョンで区切るときはタグをv1.0.0等として追加する。プレフィックスのvは無くてもOKだが付けておく。
その他一般的なバージョンの規則は以下を参考。
Composer ドキュメント日本語訳 → タグ

●使い方(利用時)

パッケージを利用する側のcomposer.json

"repositories": [
    {
        "type": "vcs",
        "url": "/path/to/my-package",
        "//url": "https://hoge.org/busyoumono99/my-package.git"
    }
],
"require": {
	  "busyoumono99/my-package": "1.*"
}

設定後にターミナルでインストール

$ composer install

元パッケージ側をgitでコミットして、新しくタグv1.1.0を追加すればアップデート出来る

$ composer update

●まとめ

以上で自作パッケージの基本的な部分の作り方、利用の仕方終わり。
何があれば、コメントか編集リクエストお願いします。

●参考

76
74
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
76
74

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?