「PHP」の版間の差分
Gnusocialjp (トーク | 投稿記録) 細 (→Guide) |
Gnusocialjp (トーク | 投稿記録) (Command-Line) |
||
185行目: | 185行目: | ||
例外が発生する処理の前に記述しておく。 | 例外が発生する処理の前に記述しておく。 | ||
=== Command-Line === | |||
Ref: [https://docs.phpunit.de/en/9.6/textui.html 3. The Command-Line Test Runner — PHPUnit 9.6 Manual]. | |||
phpunitコマンドでいろいろできる。いくつか重要なオプション、使用方法がある。 | |||
* phpunit file.php: 指定したファイルのテストを実行。 | |||
* --testsuite <name>: テストを指定。 | |||
== Language Reference == | == Language Reference == |
2024年1月20日 (土) 10:00時点における版
About
PHPはプログラミング言語だ。汎用的なプログラミング言語だが、主にウェブサーバー上のソフトウェアで使用される。
GNU socialはPHPで記述されている。他にもWordPress・NextCloudなどがPHPで記述されている。これらのPHP製ソフトウェアはVPSだけではなく安価なレンタルサーバーでも動作するため、低コストで運用することができる。
PHPの公式リファレンスは日本語版があり、わかりやすくまとまっている。
ウェブ上にはPHPに関するTipsが多く公開されており、大抵の疑問はウェブ検索で解決できる。
Version
PHPは言語の版数が上がる際、過去の版と互換性の無い破壊的変更がなされることがある。
開発者はこのリスクを軽減するために、非推奨の言語機能を避け、実行時の警告 (warning) を適切に処理するべきだ。
GNU socialは現在PHP 7系で動作する様に記述されており、PHP 8系への対応は作業途中だ。
PHP v8
PHP v8になっていろいろ更新が入った。特にPHP v7.4からv8に更新する際のポイントがあるので整理する (行事: 「12月にPHP8.3が出るので、PHP8で増えた文法をおさらいしましょうセミナー」参加報告 | PHP8対応の肝は型とエラーレベル | GNU social JP Web)。
大きく以下2点がある。
- エラーレベルの上昇。
- 型の厳格化。
エラーレベルが1段階上がったため、今までWarningで問題なかったものがFatal Errorになって動作しなくなる。他に、型が厳格になっている。
具体的には、php.ini/.user.iniで以下を指定して、PHP v7.4時点で警告にできるだけ対応しておく。
error_reporting=E_ALL ; -1
続いて、phpソースファイルに以下を記入して型を厳密にしておく。
declare(strict_types=1);
チェックツールがあるのでこれを使うと問題箇所などがわかる。
- PHP CodeSniffer
- PHPStan
- Rector
まず上記2個を試して、おまけでRectorも試すとよい。
Guide
Ref:
PHPのコーディングの推奨規約がある。PSR-12というのがメジャーな模様。GNU socialでも採用されている。
「What should I name my PHP class file? - Stack Overflow」にあるように、PSRではファイル名には記載がない。PSR-4や「PSR Naming Conventions - PHP-FIG」に記載がある程度。
ただ、「Manual - Documentation - Zend Framework」、「CakePHP Conventions - 4.x」など、他の規約があり、クラス名と同じになっている。
PHPのクラス名は大文字小文字を区別しないが、わかりにくいので大文字小文字で、クラス名と一致させておくとよさそう。
ただし、viewなど、表示に直接結びついているものは、小文字でもいいかも。ファイル名とURLパスが同じほうが分かりやすい。
PHPUnit
PHPUnitを使用すれば自動単体テスト (Unit test) が可能だ。
Version
情報源: Supported Versions of PHPUnit – The PHP Testing Framework。
PHPUnitのバージョンごとに対応しているPHPのバージョンが決まっている。
PHP v7.4に対応してい最後のバージョンはPHPUnit 9なので、当分はこれを使うのが良い。
Basic
出典: 2. Writing Tests for PHPUnit — PHPUnit 9.6 Manual。
基本的な使用方法を整理する。
- 基本的にはクラス単位で試験コードを記載。<Class>クラスの試験コードは<Class>Testの命名にする。
- <Class>Test はPHPUnit\Framwork\TestCaseを継承させる。
- 試験はpublicのtest*メソッドの命名にする。あるいは、@testのアノテーションを付ければ、命名規則に従わなくてもいい。
- test*メソッド内で、assertSame() などで、期待値との比較で試験を行う。
例:
<?php declare(strict_types=1); use PHPUnit\Framework\TestCase; final class StackTest extends TestCase { private static $dbh; private $instance; public static function setUpBeforeClass(): void { // DB接続などクラス全体の初期化処理 self::$dbh = new PDO(''); } public static function tearDownAfterClass(): void { self::$dbh = null; } protected function setUp(): void { // 該当インスタンスの生成などメソッド単位の初期化処理。 $instance = new Stack(); } public function testPushAndPop(): void { $stack = []; $this->assertSame(0, count($stack)); array_push($stack, 'foo'); $this->assertSame('foo', $stack[count($stack)-1]); $this->assertSame(1, count($stack)); $this->assertSame('foo', array_pop($stack)); $this->assertSame(0, count($stack)); } }
Depends
前回の試験で準備した結果を利用したい場合、@dependsのアノテーションでテスト関数を指定しておくと、指定したテスト関数のreturnを引数に受け継いだテスト関数を記述できる。
@dependsは複数指定でき、指定順に事前に試験が実行されて引数に渡される。
Data Provider
ある関数に対して、テストケースを用意して、複数の引数の組み合わせを試験したいことがよくある。こういうときのために、テスト関数に渡す引数を生成する関数のデータプロバイダーを指定できる。@dataProviderで関数を指定する。データプロバイダーは引数のリストを配列で返すようにする。
データ数が多い場合、名前付き配列にしておくと、どういうデータ項目で失敗したかがわかりやすい。
Iteratorオブジェクトを返してもいい。
Fixtures
出典: 4. Fixtures — PHPUnit 9.6 Manual。
テストメソッドの実行前に、テスト対象のインスタンスの生成や、DB接続など準備がいろいろある。これをFixturesと呼んでいる。この準備がけっこう手間になる。これを省力できるのがテストフレームワークの利点。
テストメソッド実行前後に共通で行える処理がある。
- setUp/tearDown: テストメソッド単位の前後処理。テスト対象インスタンスの生成など。tearDownは何もしなくてもいいことが多い。
- setUpBeforeClass/tearDownAfterClass: クラス単位の前後処理。 DB接続など。
XML Configuration File
出典:
基本はコマンドでテスト対象クラス・ファイルを指定してテストを実行する。他に、XMLの設定ファイル (phpunit.xml) でもテスト対象を指定できる。
testsディレクトリーの全*Test.phpを対象にする最小限の例は以下。
<phpunit bootstrap="src/autoload.php"> <testsuites> <testsuite name="money"> <directory>tests</directory> </testsuite> </testsuites> </phpunit>
以下のように--testsuiteで試験対象を指定して実行する。
phpunit --bootstrap src/autoload.php --testsuite money
Assertions
Ref:
基本はassertSameでテストすればいいのだが、それ以外にも例外とかいろいろ試験したいケースがあるので、メソッドを整理する。
特に例外の試験がイレギュラー。
<?php declare(strict_types=1); use PHPUnit\Framework\TestCase; final class ExceptionTest extends TestCase { public function testException(): void { $this->expectException(InvalidArgumentException::class); // Run test target code following. } }
上記のようにexpectExceptionを使う。
- expectException:
- expectExceptionCode:
- expectExceptionMessage:
- expectExceptionMessageMatches:
例外が発生する処理の前に記述しておく。
Command-Line
Ref: 3. The Command-Line Test Runner — PHPUnit 9.6 Manual.
phpunitコマンドでいろいろできる。いくつか重要なオプション、使用方法がある。
- phpunit file.php: 指定したファイルのテストを実行。
- --testsuite <name>: テストを指定。
Language Reference
Variables
Variable scope
出典: PHP: Variable scope - Manual。
関数の外で使用するとグローバルスコープになる。ただし、関数内では暗黙にはグローバル変数は使えない。未定義変数扱いになる。
なお、波括弧のブロックスコープは存在しない。
関数内でグローバル変数を参照したければ、関数内でglobalで明示的に使用したいグローバル変数を宣言する必要がある。
あるいは、$GLOBALS配列にグローバル変数が入っているのでこれを使う。
C系言語の感覚だと、波括弧でスコープが作られそうなイメージがあるが、PHPの波括弧はスコープを作らない。あくまで、関数の内部かどうか。
逆にいうと、関数内に定義される関数・クラスも基本グローバル。
子関数に変数を渡したい場合、引数かグローバル変数しかない。他に隠蔽したり、親関数からスコープを引き継ぎたい場合、無名関数を使うしか無い。
Control Structures
Source: PHP: Control Structures - Manual.
declare
Source: PHP: declare - Manual.
PHPUnitのサンプルコード (Getting Started with Version 9 of PHPUnit – The PHP Testing Framework) などで冒頭に以下の記述がある。
<?php declare(strict_types=1);
これの意味が分かっていなかったので整理する。
declare文 (construct) は、コードブロックの実行指令となる。以下の構文となる。
declare (<directive>) <statement>
<directive> はdeclareブロックの挙動を指示する。指定可能なものは以下3個だ。
- ticks
- encoding
- strict_types: =1の指定でPHPの暗黙の型変換を無効にする (ストリクトモード)。ただし、影響するのはスカラー型のみ。型が違う場合、TypeErrorの例外が発生する。
指令はファイルコンパイル時に処理されるので、リテラル値のみが使用可能で、変数や定数は使用不能。
declareブロックの <statement> は、<directive> の影響を受ける実行部だ。
declare文はグローバルスコープで使われる。登場以後のコードに影響する。ただし、他のファイルからincludeされても、親ファイルには影響しない。だから安心して使える。
型安全にするために、基本的にPHPファイルの冒頭にdeclare(strict_types=1);
を書いておいたほうがよいだろう。
Classes and Objects
The Basics
Ref: PHP: The Basics - Manual.
::class
<className>::classでクラス名の完全修飾子の文字列を取得できる。
例外の試験など、クラス名の情報が必要な時によくみかける。
PHP 8.0.0からオブジェクトに対しても::classを使用でき、元のクラス名を取得できる。その場合、get_class()と同じ。同じならPHP 7で使えないのでget_class()でいいか。
Features
Using PHP from the command line
Ref: PHP: Command line usage - Manual.
簡単なコードの確認などでPHPをコマンドラインなどから簡単に実行したいことがよくある。いくつか方法がある (PHP: Usage - Manual)。
- phpコマンドの引数にファイルを指定:
php file.php
/php -f file.php
- phpコマンドの引数にコードを指定:
php -r 'print_r(get_defined_constants());'
- phpコマンドに標準入力で読み込み:
php <file.php
標準入力が一番使いやすく感じる。