1. ファイルの基本ルール
1-1. ファイルの先頭の書き方
<?php
declare(strict_types=1);
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Traits\LoggableTrait;
use App\Repositories\ArticleRepository;
use Illuminate\Support\Facades\Auth;
1-2. declare とは
declare(ディレクティブ名 = 値); という書き方で、PHPの動作ルールを切り替えるコンパイル時の指示。
1-3. strict_types とは
型チェックを厳密にする設定(実務ではほぼこれしか使われない)。
PHPは本来、型が違っても変換できそうならこっそり変換して実行してしまう挙動を持つ。
strict_types=1 を付けない場合
function add(int $a, int $b): int
{
return $a + $b;
}
add("5", "3"); // → 8(文字列"5"と"3"が自動でintに変換される)
add(5.9, 1); // → 6(float 5.9が強制的にintの5に変換される。小数点以下は切り捨て)
add(true, false); // → 1(true→1、false→0に変換される)
strict_types=1 を付けた場合
型が完全に一致していないと受け付けなくなる。
declare(strict_types=1);
function add(int $a, int $b): int
{
return $a + $b;
}
add("5", "3"); // TypeError! 文字列はintに変換されない
add(5.9, 1); // TypeError! floatはintに変換されない
add(true, false); // TypeError! boolはintに変換されない
add(5, 3); // OK。型がぴったり一致
1-4. declare のルール
- ファイルの一番最初の文に書く(
namespaceよりも前) - 各ファイルごとに個別の設定が必要
2. namespace(名前空間)
2-1. namespaceとは
今のファイルの「住所」を宣言するもの。
PHPプロジェクトには多くのクラスが存在するため、名前だけで管理すると以下のように名前が被ることがある。
class Controller { ... } // app/Http/Controllers/Controller.php
class Controller { ... } // 別の誰かが別の場所に、同じ名前で作ってしまった
PHPは同じ名前のクラスが2つある状況をエラーと判断する。プロジェクトが大きくなるほど名前の衝突は起きやすく危険なので、namespaceで「住所」の仕組みを使って衝突を防ぐ。
namespace App\Http\Controllers\Admin; // これから定義するクラスはこの住所に置くという宣言
class ArticleController
{
}
クラス名には/を書けないため、PHPが自動的にnamespace宣言とクラス名を合体させて正式名称を作る。
App\Http\Controllers\Admin\ArticleController
2-2. Laravelのルール
Laravelでは「住所(namespace)=フォルダ名」と一致させる。
namespace App\Http\Controllers\Admin;
↓ 対応 ↓
app/Http/Controllers/Admin/ ← このファイルは必ずこのフォルダにある
2-3. 同じ住所内のクラスを呼ぶ場合
同じスコープ(namespace)内にある別クラスは、継承時にuseなしで呼べる。
namespace App\Http\Controllers\Admin;
class ArticleController extends Controller
// ↑ Controllerが同じAdminフォルダ内にあれば、useなしでこのまま使える
{
}
2-4. 違う住所にあるクラスを呼ぶ場合
useを使って呼ぶ。短い名前で呼べるようにする宣言で、書かないと毎回フルパスを書く必要がある。
use App\Http\Controllers\Controller;
名前が被った場合はasで別名をつける。
use App\Http\Controllers\Controller;
use Vendor\Package\Controllers\Dashboard as VendorDashboard;
3. extends(継承)とは
class Animal
{
public function eat()
{
return "食べる";
}
}
class Dog extends Animal
{
public function bark()
{
return "ワン";
}
}
DogはAnimalをextendsしているため、Dogのインスタンスは自分自身に書いていないメソッドまで使える。
$dog = new Dog();
$dog->bark(); // "ワン" ← Dog自身に書いたメソッド
$dog->eat(); // "食べる" ← Animalから継承したメソッド。Dogには書いてないのに使える
4. 変数とデータ型
// app/Http/Controllers/Admin/ArticleController.php より
$loggedCategoryId = Auth::user()->category_id; // int が入る想定の変数
if ($loggedCategoryId <= 0) {
$categories = $this->categoryRepository->getSelectOptionList();
}
- 変数名には
$をつける - オブジェクトのプロパティにアクセスするには
->を使う
5. アクセス修飾子
| 修飾子 | アクセス範囲 |
|---|---|
public |
どこからでも(クラスの外からでも) |
protected |
このクラスと、これを継承した子クラスの中だけ |
private |
このクラスの中だけ |
アクセス修飾子がある理由
すべてをpublicにすると、そのクラスを使っている別ファイルのどこからでもアクセスできてしまい、エラーが出た時の影響範囲が大きくなる。protected/privateで影響範囲を閉じ込めておけば、バグが起きた時にそのクラスの中だけを見ればよくなる。
6. スコープ定義演算子(::)
同じ名前の定数が複数のクラスに存在してもいいように、どのクラスをスコープしているかをこの記号で確定させる。
class Feature
{
public const DISTRIBUTION_STATUS_UNDELIVERED = 0;
}
class Stamp
{
public const DISTRIBUTION_STATUS_UNDELIVERED = 1; // 同じ名前だが別物
}
DISTRIBUTION_STATUS_UNDELIVERED // これだけでは、どっちのクラスの話?
Feature::DISTRIBUTION_STATUS_UNDELIVERED // 「Featureのスコープの方だよ」と解決している
Stamp::DISTRIBUTION_STATUS_UNDELIVERED // 「Stampのスコープの方だよ」と解決している
左側にクラス名(=スコープ)を書くことで、「このスコープに属する名前を指している」ことを明示できる。