PHP
24.2.27
公式ドキュメントページに目を通しておきたい。あとphp-fpmについても。
https://www.php.net/manual/ja/
https://zenn.dev/bs_kansai/articles/3706c12408160c
PHP ドキュメント読む
Evernoteからの写し。
Laravelに関する部分を中心に抽出。例外処理とかも。
オブジェクト
いわゆるクラス
code:php
// クラス
class Post
{
// プロパティ
public $text;
public $likes;
// メソッド
public function show()
{
printf('%s (%d)' . PHP_EOL, $this->text, $this->likes);
}
}
$posts = [];
// インスタンス生成 ()はあってもなくてもどちらでもOK
$posts0 = new Post();
$posts0->text = 'hello';
$posts0->likes = 0;
$posts0->show();
--- 結果
hello (0)
コンストラクタ
値を渡さないままインスタンスを生成することはできない。
code:php
class Post
{
public $text;
public $likes;
public function __construct($textFromNew, $likesFromNew)
{
$this->text = $textFromNew;
$this->likes = $likesFromNew;
}
public function show()
{
printf('%s (%d)' . PHP_EOL, $this->text, $this->likes);
}
}
$posts0 = new Post('hello',0);
アクセス修飾子
private, publicなど。
code:php
class Post
{
public $text;
private $likes = 0;
}
$p = new Post();
$p->likes++; // これできない 行うときは、Postクラスの中に++をするメソッドをpublicで定義して行う。#08
クラス自身のプロパティとメソッドを定義する static
静的メソッド。クラス内のプロパティを使うときは、self::変数名。
code:php
class Post
{
private $text;
private static $count = 0;
public function __construct($text)
{
$this->text = $text;
// クラスプロパティを操作する self::定義名
self::$count++;
}
public static function showInfo()
{
printf('Count: %d' . PHP_EOL, self::$count);
}
}
$posts = [];
$posts0 = new Post('hello');
$posts1 = new Post('hello again');
// クラスメソッドを呼び出す クラス::メソッド名
Post::showInfo();
定数の定義
慣習的に大文字、$もいらない
クラス内で定義する
code:php
class Post
{
// 定数
private const VERSION = 0.1;
public const VER = 0.2;
public static function showInfo()
{
// constの場合もstaticと似た扱い self::名前で呼び出す
printf('Version: %.1f' . PHP_EOL, self::VERSION);
}
}
$posts = [];
$posts0 = new Post();
$posts1 = new Post();
// プライベートの定数はメソッドで、パブリックはクラス名::定数名で呼び出せる
Post::showInfo();
echo Post::VER . PHP_EOL;
--- 結果 ---
Version: 0.1
0.2
継承
code:php
class SponsoredPost extends Post {
// 親の今すたらくたを使う
parent::__construct($text)
{
}
}
$posts2 = new SponsoredPost('hello hello');
$posts2->show();
オーバーライド
public どこでも呼べる
protected 親と子のクラスで使える
private 定義したクラスでのみ呼べる
code:php
class Post {
protected $text;
public function show() {
...
}
}
class SponsoredPost extends Post {
private $sponsor;
// オーバーライド $this->textは、親で定義したものを持ってきている
public function show() {
printf('%s ADS BY %s' . PHP_EOL, $this->text, $this->sponsor);
}
}
型の継承
子クラスを作るとメソッド、プロパティも継承されるが、データの型自体も継承される
つまり、SponsoredPostはPost型としても使用できる
code:php
function processPost(Post $post) {
$post->show();
}
$p = new Post();
$sp = new SponsoredPost();
processPost($p);
processPost($sp); // これもOK
抽象クラス
継承前提のクラス。それ自体からインスタンスは生成できない。
code:php
// abstract classという形で作成する
abstract class BasePost {
// 定義予定のメソッドだけabstract...で定義しておく。
abstract public function show();
}
こんな感じ
code:php
abstract class BaseAnimal {
abstract public function __construct($name);
abstract public function echoName();
}
class Animal extends BaseAnimal {
public $name;
public function __construct($name) {
$this->name = $name;
}
public function echoName() {
echo $this->name;
}
}
$a = new Animal('kirin');
$a->echoName();
インターフェース
抽象クラスから3つくらい、継承したものを作る
うち2つに新しいメソッドを追加したいが、抽象クラスに定義すると残り1つでも定義しないとエラーになる
そういう時に使う
code:php
interface NewMethodInterface {
public function newMethod();
}
// implementsで読み込ませることで使えるようになる
class Animal extends BaseAnimal implements NewMethodInterface {
public function newMethod() {
...
}
}
インターフェースでの型継承
extendsと同じように、インターフェースも型が同じになる
code:php
function processNewMethod(NewMethodInterface $interface) {
$interface->...();
}
実際使う時に調べてみる。
トレイト
抽象クラスでは、定義したいメソッドをとりあえずabstractで書いておける
ただもちろん、それぞれ子クラスを作ったらそれに関して内容を記述する必要がある
同じ処理だったら、処理が重複する。
abstractには詳細な処理はかけない。インターフェースも詳細な処理は書けない。
そういう時に使う。use トレイト名とすることで、コードの断片を使いまわせる
PHPの中で、Laravelと密接に関係しそうな部分
code:php
// トレイトを定義
trait LikeTrait {
private $likes = 0;
public function like() {
$this->likes++;
}
}
abstract class BasePost {
protectaed $text;
public function __construct($text) {
$this->text = $text;
}
abstract public function show();
}
// 子クラスその1
class Post extends BasePost implements LikeInterface {
// トレイトに記述したコードを呼び出す
use LikeTrait;
public function show() {
printf('%s (%d)' . PHP_EOL, $this->text, $this->likes);
}
}
// 子クラスその2
class PremiumPost extends BasePost implements LikeInterface {
// トレイトを呼び出す
use LikeTrait;
private $price;
public function __construct($text, $price) {
parent::__construct($text);
$this->price = $price;
}
public function show() {
printf('%s (%d) %d JPY' . PHP_EOL, $this->text, $this->likes, $this->price);
}
}
requireとオートロード
spl_autoload_registerとは
クラスからインスタンスを生成する際に呼ばれるPHPの内部の仕組み。
クラスが未定義であることをフックに、登録しておいたメソッドを実行させる
難しい。直接定義することは少ないが、Laravelと関連性があるので気になったら深掘りする。
code:php
// 動きとしては、newクラスをして、クラスが読み込まれていなかったら以下の処理が走るという関数になっている。
spl_autoload_register(function ($class) {
require($class . '.php');
});
// この辺はspl_autoload_registerが呼ばれている
$p = new Post();
$m = new Menu('curry', '750Yen');
名前空間 namespace
複数人で開発していると、実装するクラス名が被ることがある
AブランチとBブランチでspecialMenuというクラスを定義してしまった場合とか
クラスを定義している先頭で好きな名前をつけることで、そのクラスに名前をつけてやることができる
好きな名前でOKだが、基本ベンダ名\プロジェクト名みたいな形でするっぽい
Laravelと深く関わる機能
code:php
# Post.php
namespace Dotinstall\KirThread;
class Post {
...
}
/* -------------- */
# MainCode.php
use Dotinstall\KirThread; // A
use Dotinstall\KirThread as KirThread; // asで言い換えverを作ることができる。Aと同じ意味
require ('Post.php');
class Post {
...
}
// Post.phpで定義した方のPostクラスが呼ばれる
$p = new Dotinstall\KirThread\Post('aaa'); // A
$p2 = new KirThread\Post('aa'); // asで名前をつけた方
例外処理
PHP内部のExceptionクラスを利用している
エラーを投げる (エラーを自作する)
code:php
class Post {
private $text;
function __construct($text)
{
// $text <= 3なら、エラーを投げる
if (strlen($text) <= 3) {
throw new Exception('Text too short!');
}
$this->text = $text;
}
function show()
{
printf('%s' . PHP_EOL, $this->text);
}
}
// エラーが起こる
$p = new Post('a');
/*
PHP Fatal error: Uncaught Exception: Text too short! in /workspace/Main.php:9
Stack trace:
#0 /workspace/Main.php(20): Post->__construct()
*/
try ~ catchで呼び出す
例外が起こりそうな箇所をtryで囲う。
code:php
class Post { ... } // 上のPostと同じ
try {
$c = new Post('a');
} catch (Exception $e) {
echo $e->getMessage(); // 'Text too short!'というエラーメッセージがechoされる
echo $e->getCode();
}
Exceptionクラスの便利なメソッドを覚えておくと良い
https://www.php.net/manual/ja/class.exception.php
echo $e->getLine();は例外を投げられた行など、いろいろある
finally
問題があるなしにかかわらず、tryとcatchが済んだ後に流れる処理
Rubyで言うensure
code:php
echo "start\n";
try {
$date = new DateTime("199x-01-01"); // 1996-01-01とかじゃないとダメなのでcatchが走る
echo $date->format('Y/m/d')."\n";
} catch (Exception $e) {
echo $e->getMessage()."\n"; // エラーメッセージがechoされる
} finally {
echo "end\n"; // catch処理が終わったら走る
}