PHPのクラスメソッドについて

採用はこちら

PHPでは、クラスの中に定義された関数を「メソッド」と呼びます。

メソッドは、クラスが持つ処理や振る舞いを表現するために使用します。

たとえば、ユーザー情報を取得する、商品価格を計算する、メールアドレスを変更するといった処理をメソッドとして定義できます。

class User
{
    public function getName(): string
    {
        return '田中';
    }
}

このコードでは、getName()がメソッドです。

ただし、「クラスメソッド」という言葉は、文脈によってstaticメソッドを意味する場合があります。

PHPのメソッドは、主に次の2種類に分けて考えると分かりやすくなります。

  • インスタンスメソッド
  • staticメソッド

本記事では、主にPHP 8.0以降のモダンなPHPを前提に、クラスメソッドの仕組みや使い方を解説します。

目次

インスタンスメソッド

インスタンスメソッドの基本

インスタンスメソッドは、クラスから生成したオブジェクトを通して呼び出すメソッドです。

class User
{
    public function greet(): string
    {
        return 'こんにちは';
    }
}

$user = new User();

echo $user->greet();

メソッドを呼び出すときは、->を使用します。

$user->greet();

基本的な形式は次のとおりです。

$オブジェクト->メソッド名();

$thisとは

$thisは、現在そのメソッドを実行しているオブジェクト自身を表します。

class User
{
    public string $name;

    public function getName(): string
    {
        return $this->name;
    }
}

$this->nameは、「現在のオブジェクトが持つnameプロパティ」という意味です。

$user1 = new User();
$user1->name = '佐藤';

$user2 = new User();
$user2->name = '鈴木';

echo $user1->getName(); // 佐藤
echo $user2->getName(); // 鈴木

同じUserクラスから生成したオブジェクトでも、それぞれ異なる値を保持できます。

$thisはクラスそのものではなく、実際に生成された個別のオブジェクトを指します。

メソッドの引数と戻り値

メソッドに引数を渡す

通常の関数と同じように、メソッドにも引数を渡せます。

class Calculator
{
    public function add(int $a, int $b): int
    {
        return $a + $b;
    }
}

$calculator = new Calculator();

echo $calculator->add(10, 20);

実行結果は次のとおりです。

30

戻り値の型を指定する

メソッド名の後ろに型を記述すると、戻り値の型を指定できます。

public function add(int $a, int $b): int

このコードでは、引数の$a$bintとして宣言し、戻り値もintとして宣言しています。

代表的な型には、次のようなものがあります。

string
int
float
bool
array
object
mixed
void

たとえば、文字列を返すメソッドは次のように記述します。

public function getName(): string
{
    return '田中';
}

配列を返す場合は、次のようにします。

public function getItems(): array
{
    return ['A', 'B', 'C'];
}

strict_typesによる違い

PHPでは、型宣言を記述しても、常に完全に厳密な型チェックが行われるとは限りません。

strict_typesを有効にしていない場合、変換可能なスカラー値が自動的に変換されることがあります。

class Calculator
{
    public function add(int $a, int $b): int
    {
        return $a + $b;
    }
}

$calculator = new Calculator();

echo $calculator->add('10', '20');

数値として解釈できる文字列は、整数へ変換される場合があります。

厳密な型チェックを行うには、PHPファイルの先頭に次の宣言を記述します。

<?php

declare(strict_types=1);

完全な例は次のとおりです。

<?php

declare(strict_types=1);

class Calculator
{
    public function add(int $a, int $b): int
    {
        return $a + $b;
    }
}

$calculator = new Calculator();

echo $calculator->add('10', '20');

この場合、文字列を渡すとTypeErrorが発生します。

なお、strict_typesは、基本的にメソッドを定義したファイルではなく、呼び出した側のファイルの宣言が影響します。

デフォルト引数

引数には初期値を設定できます。

class Message
{
    public function create(
        string $name,
        string $greeting = 'こんにちは'
    ): string {
        return "{$greeting}、{$name}さん";
    }
}

$message = new Message();

echo $message->create('山田');

実行結果は次のとおりです。

こんにちは、山田さん

第2引数を指定すると、初期値を上書きできます。

echo $message->create(
    '山田',
    'おはようございます'
);

原則として、デフォルト値を持つ引数は後ろに配置します。

アクセス修飾子

アクセス修飾子は、メソッドをどこから呼び出せるかを制御するために使用します。

PHPの主なアクセス修飾子は次の3種類です。

アクセス修飾子アクセスできる範囲
publicクラスの内外からアクセスできる
protected定義クラスと継承先からアクセスできる
private定義したクラス内からのみアクセスできる

publicメソッド

publicメソッドは、クラスの外部から呼び出せます。

class User
{
    public function greet(): string
    {
        return 'こんにちは';
    }
}

$user = new User();

echo $user->greet();

外部に公開する必要がある操作には、publicを使用します。

protectedメソッド

protectedメソッドは、定義元のクラスと、そのクラスを継承した子クラスから呼び出せます。

class Animal
{
    protected function getSound(): string
    {
        return '鳴き声';
    }
}

class Dog extends Animal
{
    public function speak(): string
    {
        return $this->getSound();
    }
}

$dog = new Dog();

echo $dog->speak();

クラスの外部から直接呼び出すことはできません。

$dog->getSound();

このコードはエラーになります。

privateメソッド

privateメソッドは、そのメソッドを定義したクラス内からのみ呼び出せます。

class UserService
{
    public function register(): void
    {
        $this->validate();
        $this->save();
    }

    private function validate(): void
    {
        // 入力値の検証
    }

    private function save(): void
    {
        // 保存処理
    }
}

外部のコードは、register()だけを呼び出します。

$service = new UserService();

$service->register();

次のように、privateメソッドを外部から直接呼び出すことはできません。

$service->validate();

また、privateメソッドは子クラスからも直接呼び出せません。

class ParentClass
{
    private function execute(): void
    {
    }
}

class ChildClass extends ParentClass
{
    public function run(): void
    {
        $this->execute();
    }
}

このコードはエラーになります。

子クラスでも利用したい場合は、protectedを使用します。

staticメソッド

staticメソッドの基本

staticメソッドは、オブジェクトを生成せずに呼び出せるメソッドです。

class Calculator
{
    public static function add(int $a, int $b): int
    {
        return $a + $b;
    }
}

echo Calculator::add(10, 20);

呼び出しには::を使用します。

クラス名::メソッド名();

staticメソッドでは$thisを使えない

staticメソッドは、特定のオブジェクトに属する処理ではありません。

そのため、staticメソッド内では$thisを使用できません。

class User
{
    public string $name = '田中';

    public static function getName(): string
    {
        return $this->name;
    }
}

このコードはエラーになります。

staticプロパティへアクセスする場合は、self::などを使用します。

class Tax
{
    private static float $rate = 0.1;

    public static function calculate(int $price): float
    {
        return $price * self::$rate;
    }
}

echo Tax::calculate(1000);

実行結果は次のとおりです。

100

staticメソッドをオブジェクト経由で呼ぶ場合

PHPでは、staticメソッドをオブジェクト経由で呼び出せる場合があります。

$calculator = new Calculator();

echo $calculator->add(10, 20);

ただし、staticメソッドであることを明確にするため、通常はクラス名を使用します。

Calculator::add(10, 20);

オブジェクト経由で呼び出すと、インスタンスの状態を利用するメソッドだと誤解されやすいためです。

非staticメソッドはクラス名から呼び出せない

PHP 8以降では、非staticメソッドをstaticメソッドのように呼び出すことはできません。

class User
{
    public function getName(): string
    {
        return '田中';
    }
}

echo User::getName();

このコードはエラーになります。

インスタンスメソッドとstaticメソッドの違い

インスタンスメソッドとstaticメソッドの主な違いは次のとおりです。

項目インスタンスメソッドstaticメソッド
オブジェクト生成必要不要
呼び出し方$object->method()ClassName::method()
$this使用できる使用できない
オブジェクトごとの状態扱える基本的に扱わない
主な用途ユーザー、商品、注文など計算、変換、補助処理など

オブジェクトごとの状態を扱う場合は、インスタンスメソッドが適しています。

class User
{
    public function __construct(
        private string $name
    ) {
    }

    public function getName(): string
    {
        return $this->name;
    }
}

特定のオブジェクト状態に依存しない計算や変換処理では、staticメソッドを利用できます。

class StringHelper
{
    public static function uppercase(
        string $text
    ): string {
        return strtoupper($text);
    }
}

ただし、何でもstaticメソッドにすると、依存関係が見えにくくなり、テストや変更が難しくなる場合があります。

コンストラクタ

コンストラクタの基本

コンストラクタは、オブジェクトを生成したときに自動で実行される特殊なメソッドです。

class User
{
    public string $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }
}

$user = new User('田中');

echo $user->name;

コンストラクタ名は、__constructで固定されています。

public function __construct()
{
}

コンストラクタプロパティプロモーション

PHP 8.0以降では、コンストラクタプロパティプロモーションを利用できます。

class User
{
    public function __construct(
        public string $name,
        public string $email
    ) {
    }
}

この記述は、プロパティ宣言とコンストラクタ内の代入をまとめたものです。

$user = new User(
    name: '田中',
    email: 'tanaka@example.com'
);

親クラスのコンストラクタ

子クラスが独自のコンストラクタを定義した場合、親クラスのコンストラクタは自動では呼び出されません。

class ParentClass
{
    public function __construct()
    {
        echo '親のコンストラクタ';
    }
}

class ChildClass extends ParentClass
{
    public function __construct()
    {
        echo '子のコンストラクタ';
    }
}

親クラスのコンストラクタも実行する場合は、parent::__construct()を呼び出します。

class ChildClass extends ParentClass
{
    public function __construct()
    {
        parent::__construct();

        echo '子のコンストラクタ';
    }
}

メソッドから別のメソッドを呼び出す

同じクラス内のインスタンスメソッドを呼び出す場合は、$this->を使用します。

class Order
{
    public function complete(): void
    {
        $this->validate();
        $this->save();
        $this->sendNotification();
    }

    private function validate(): void
    {
        echo '注文内容を確認します' . PHP_EOL;
    }

    private function save(): void
    {
        echo '注文を保存します' . PHP_EOL;
    }

    private function sendNotification(): void
    {
        echo '通知を送信します' . PHP_EOL;
    }
}

利用側は次のようになります。

$order = new Order();

$order->complete();

外部のコードはcomplete()だけを呼び出し、内部処理の順序や詳細はクラス側が管理します。

継承とメソッド

継承の基本

PHPでは、既存クラスを継承して新しいクラスを作成できます。

class Animal
{
    public function eat(): string
    {
        return '食べます';
    }
}

class Dog extends Animal
{
    public function bark(): string
    {
        return 'ワン';
    }
}

$dog = new Dog();

echo $dog->eat();
echo $dog->bark();

DogクラスはAnimalクラスを継承しているため、eat()メソッドも利用できます。

メソッドのオーバーライド

親クラスのメソッドを子クラス側で再定義することを、オーバーライドと呼びます。

class Animal
{
    public function speak(): string
    {
        return '動物の鳴き声';
    }
}

class Dog extends Animal
{
    public function speak(): string
    {
        return 'ワンワン';
    }
}

class Cat extends Animal
{
    public function speak(): string
    {
        return 'ニャー';
    }
}

同じspeak()メソッドでも、オブジェクトの種類によって異なる動作を実装できます。

オーバーライド時の互換性

メソッドをオーバーライドするときは、親メソッドと互換性のある引数型や戻り値型にする必要があります。

class ParentClass
{
    public function process(string $value): string
    {
        return $value;
    }
}

次のように、互換性のない型へ変更するとエラーになります。

class ChildClass extends ParentClass
{
    public function process(int $value): array
    {
        return [$value];
    }
}

また、親クラスでpublicだったメソッドを、子クラスでprotectedprivateへ狭めることはできません。

class ParentClass
{
    public function execute(): void
    {
    }
}

class ChildClass extends ParentClass
{
    protected function execute(): void
    {
    }
}

この定義はエラーになります。

self::static::parent::

self::

self::は、そのコードが定義されているクラスを基準に参照します。

class ParentClass
{
    public static function getName(): string
    {
        return 'Parent';
    }

    public static function showName(): string
    {
        return self::getName();
    }
}

class ChildClass extends ParentClass
{
    public static function getName(): string
    {
        return 'Child';
    }
}

echo ChildClass::showName();

実行結果は次のとおりです。

Parent

self::は、showName()が定義されているParentClassを参照します。

static::

static::は、実際に呼び出されたクラスを基準に参照します。

class ParentClass
{
    public static function getName(): string
    {
        return 'Parent';
    }

    public static function showName(): string
    {
        return static::getName();
    }
}

class ChildClass extends ParentClass
{
    public static function getName(): string
    {
        return 'Child';
    }
}

echo ChildClass::showName();

実行結果は次のとおりです。

Child

この仕組みを遅延静的束縛と呼びます。

parent::

parent::は、親クラスのメソッドやコンストラクタを呼び出すときに使用します。

class User
{
    public function getMessage(): string
    {
        return 'ユーザーです';
    }
}

class AdminUser extends User
{
    public function getMessage(): string
    {
        return parent::getMessage()
            . '。管理者権限があります';
    }
}

基本的には、次のように覚えると分かりやすくなります。

  • self:::定義元のクラス
  • static:::実際に呼び出されたクラス
  • parent:::親クラス

finalメソッド

finalを付けたメソッドは、子クラスでオーバーライドできません。

class Payment
{
    final public function execute(): void
    {
        echo '決済を実行します';
    }
}

重要な処理を子クラス側で変更させたくない場合に使用します。

クラス自体にfinalを付けることもできます。

final class Payment
{
}

finalクラスは継承できません。

抽象メソッド

抽象メソッドは、親クラス側で処理内容を定義せず、子クラスへ実装を要求するメソッドです。

abstract class Payment
{
    abstract public function pay(int $amount): void;
}

子クラスは、原則として抽象メソッドを実装する必要があります。

class CreditCardPayment extends Payment
{
    public function pay(int $amount): void
    {
        echo "クレジットカードで"
            . "{$amount}円を支払います";
    }
}

class BankTransferPayment extends Payment
{
    public function pay(int $amount): void
    {
        echo "銀行振込で{$amount}円を支払います";
    }
}

抽象クラスは直接インスタンス化できません。

$payment = new Payment();

このコードはエラーになります。

インターフェース

インターフェースは、クラスが実装すべきメソッドのルールを定義します。

interface LoggerInterface
{
    public function log(string $message): void;
}

インターフェースを実装するクラスは、定義されたメソッドを実装します。

class FileLogger implements LoggerInterface
{
    public function log(string $message): void
    {
        echo "ファイルに記録します: {$message}";
    }
}

class DatabaseLogger implements LoggerInterface
{
    public function log(string $message): void
    {
        echo "データベースに記録します: {$message}";
    }
}

インターフェースを型として受け取ることもできます。

function saveLog(LoggerInterface $logger): void
{
    $logger->log('処理が完了しました');
}

この設計により、具体的なクラスではなく、共通の契約に依存できます。

nullable型

値がnullになる可能性がある場合は、型の前に?を付けます。

class UserRepository
{
    public function findById(int $id): ?string
    {
        if ($id === 1) {
            return '田中';
        }

        return null;
    }
}

?stringは、次の2種類の値を返せることを示します。

string
null

次の書き方とほぼ同じ意味です。

public function findById(
    int $id
): string|null {
}

nullable型は、PHP 7.1以降で利用できます。

union型

複数の型を許可する場合は、|を使用します。

class Formatter
{
    public function format(
        int|float $value
    ): string {
        return number_format($value);
    }
}

このメソッドは、intまたはfloatを受け取れます。

union型はPHP 8.0以降で利用できます。

void型

voidは、メソッドが戻り値を返さないことを表します。

public function save(): void
{
    echo '保存しました';
}

値を伴わないreturn;は使用できます。

public function save(): void
{
    if (!$this->isValid()) {
        return;
    }

    // 保存処理
}

一方、値を返すことはできません。

public function save(): void
{
    return true;
}

このコードはエラーになります。

可変長引数

引数の数が決まっていない場合は、...を使用します。

class Calculator
{
    public function sum(int ...$numbers): int
    {
        return array_sum($numbers);
    }
}

$calculator = new Calculator();

echo $calculator->sum(10, 20, 30, 40);

実行結果は次のとおりです。

100

メソッド内では、$numbersは配列として扱われます。

配列を展開して渡すこともできます。

$numbers = [10, 20, 30, 40];

echo $calculator->sum(...$numbers);

名前付き引数

PHP 8.0以降では、引数名を指定してメソッドを呼び出せます。

class UserService
{
    public function create(
        string $name,
        string $email,
        bool $isActive
    ): void {
        // ユーザー作成処理
    }
}

$service = new UserService();

$service->create(
    name: '田中',
    email: 'tanaka@example.com',
    isActive: true
);

名前付き引数を使用すると、それぞれの値の意味が分かりやすくなります。

ただし、名前付き引数が利用されている場合、メソッドの引数名もAPIの一部になります。

public function create(string $name): void
{
}

呼び出し側が次のようになっているとします。

$service->create(name: '田中');

引数名を変更すると、既存の呼び出しが動かなくなります。

public function create(
    string $userName
): void {
}

公開メソッドの引数名は、不用意に変更しないことが重要です。

メソッドチェーン

メソッドの戻り値として$thisを返すと、連続してメソッドを呼び出せます。

class QueryCondition
{
    private array $conditions = [];

    public function where(
        string $column,
        string $value
    ): self {
        $this->conditions[] = [
            'column' => $column,
            'value' => $value,
        ];

        return $this;
    }

    public function getConditions(): array
    {
        return $this->conditions;
    }
}

次のように連続して呼び出せます。

$query = new QueryCondition();

$conditions = $query
    ->where('status', 'active')
    ->where('role', 'admin')
    ->getConditions();

メソッドチェーンを成立させているのは、次の部分です。

return $this;

現在のオブジェクト自身を返すことで、その戻り値に対して別のメソッドを呼び出せます。

SQLへ値を直接埋め込まない

メソッドチェーンの例でSQLを生成する場合でも、値をSQL文字列へ直接埋め込むべきではありません。

次のようなコードは危険です。

$sql = "SELECT * FROM users "
    . "WHERE status = '{$status}'";

入力値によっては、SQLインジェクションにつながる可能性があります。

実務では、PDOのプリペアドステートメントを使用します。

$stmt = $pdo->prepare(
    'SELECT * FROM users '
    . 'WHERE status = :status'
);

$stmt->execute([
    'status' => $status,
]);

値はプレースホルダーへ渡し、SQL文字列へ直接連結しないことが重要です。

マジックメソッド

マジックメソッドは、特定の操作が行われたときに自動で呼び出される特殊なメソッドです。

代表的なマジックメソッドには、次のものがあります。

メソッド呼び出されるタイミング
__construct()オブジェクト生成時
__destruct()オブジェクト破棄時
__toString()オブジェクトを文字列として扱ったとき
__get()アクセス不能なプロパティを取得したとき
__set()アクセス不能なプロパティへ代入したとき
__call()アクセス不能なメソッドを呼び出したとき
__callStatic()アクセス不能なstaticメソッドを呼び出したとき
__invoke()オブジェクトを関数のように呼び出したとき
__isset()isset()などが実行されたとき
__unset()unset()が実行されたとき
__clone()オブジェクトが複製されたとき
__debugInfo()デバッグ情報が取得されたとき

__toString()

__toString()は、オブジェクトを文字列として扱ったときに呼び出されます。

class User
{
    public function __construct(
        private string $name
    ) {
    }

    public function __toString(): string
    {
        return $this->name;
    }
}

$user = new User('田中');

echo $user;

実行結果は次のとおりです。

田中

__invoke()

__invoke()は、オブジェクトを関数のように呼び出したときに実行されます。

class PriceFormatter
{
    public function __invoke(int $price): string
    {
        return number_format($price) . '円';
    }
}

$formatter = new PriceFormatter();

echo $formatter(10000);

実行結果は次のとおりです。

10,000円

マジックメソッドは便利ですが、処理が暗黙的になりやすいため、多用するとコードの流れを追いにくくなることがあります。

メールアドレスを扱うクラスの設計例

変更時だけでなく生成時にも検証する

メールアドレスの形式を保証したい場合は、変更時だけでなく、オブジェクト生成時にも検証する必要があります。

class User
{
    private string $email;

    public function __construct(
        private string $name,
        string $email
    ) {
        $this->changeEmail($email);
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function getEmail(): string
    {
        return $this->email;
    }

    public function changeEmail(
        string $newEmail
    ): void {
        if (
            filter_var(
                $newEmail,
                FILTER_VALIDATE_EMAIL
            ) === false
        ) {
            throw new InvalidArgumentException(
                '正しいメールアドレスを'
                . '入力してください'
            );
        }

        $this->email = $newEmail;
    }
}

コンストラクタからchangeEmail()を呼び出すことで、生成時と変更時に同じ検証ルールを適用できます。

$user = new User(
    name: '田中',
    email: 'tanaka@example.com'
);

不正なメールアドレスを渡すと、例外が発生します。

$user = new User(
    name: '田中',
    email: '不正な値'
);

形式チェックだけでは確認できないこと

FILTER_VALIDATE_EMAILで確認できるのは、主にメールアドレスの形式です。

次の内容までは確認できません。

  • ドメインが実在するか
  • メールを実際に受信できるか
  • 本人が所有するメールアドレスか
  • 一時的なメールアドレスか

ユーザー登録では、確認メールを送信し、本人がリンクをクリックしたことを確認する仕組みが必要になる場合があります。

staticメソッドを多用しない

staticメソッドは便利ですが、多用すると依存関係が見えにくくなることがあります。

class UserService
{
    public function register(): void
    {
        Mailer::send();
        Logger::write();
    }
}

この設計では、MailerLoggerへの依存がクラス内部に固定されています。

依存性注入を利用すると、必要な依存関係を外部から渡せます。

class UserService
{
    public function __construct(
        private MailerInterface $mailer,
        private LoggerInterface $logger
    ) {
    }

    public function register(): void
    {
        $this->mailer->send();
        $this->logger->write();
    }
}

この形にすると、テスト用の実装へ差し替えやすくなります。

ただし、状態を持たない単純な計算や文字列変換にstaticメソッドを使うことが、必ずしも悪いわけではありません。

メソッドとクラスの責務を分ける

メソッドを小さくする

1つのメソッドに多くの処理を詰め込むと、内容を理解しにくくなります。

public function registerUser(): void
{
    // 入力値検証
    // パスワードのハッシュ化
    // データベース保存
    // メール送信
    // ログ記録
}

処理をメソッド単位に分けると、流れを理解しやすくなります。

public function registerUser(): void
{
    $this->validate();
    $this->hashPassword();
    $this->save();
    $this->sendWelcomeEmail();
    $this->writeLog();
}

メソッド分割と責務分離は異なる

メソッドを分けただけでは、クラスの責務が分離されたとは限りません。

同じクラスが次の処理をすべて担当している場合、責務が多すぎる可能性があります。

  • 入力値の検証
  • パスワード処理
  • データベース保存
  • メール送信
  • ログ記録

規模が大きくなった場合は、別クラスへ分けることも検討します。

class UserRegistrationService
{
    public function __construct(
        private UserValidator $validator,
        private PasswordHasher $passwordHasher,
        private UserRepository $userRepository,
        private MailerInterface $mailer,
        private LoggerInterface $logger
    ) {
    }
}

メソッドを小さくすることと、クラスの責務を分けることは、似ていますが別の設計上の考え方です。

メソッド名の付け方

メソッド名から処理内容が分かるようにすることが重要です。

分かりにくい名前は避けます。

public function execute(): void
{
}

処理内容が明確な名前にします。

public function sendWelcomeEmail(): void
{
}

よく使われる命名例は次のとおりです。

getName()
findUser()
calculateTotal()
createOrder()
updateProfile()
deleteAccount()

boolを返すメソッド

boolを返すメソッドは、ishasなどで始めると意味が分かりやすくなります。

public function isActive(): bool
{
    return $this->status === 'active';
}
public function hasPermission(
    string $permission
): bool {
    return in_array(
        $permission,
        $this->permissions,
        true
    );
}

呼び出し側も自然に読めます。

if ($user->isActive()) {
    // 処理
}
if ($user->hasPermission('edit')) {
    // 処理
}

getを使うメソッド

getで始まるメソッドは、一般的に値を取得する処理を想像させます。

public function getName(): string
{
    return $this->name;
}

値の取得以外に、登録やメール送信などの副作用を伴う処理を行う場合は、get以外の名前を使用したほうが分かりやすくなります。

publicメソッドを増やしすぎない

外部から呼び出す必要がないメソッドは、privateまたはprotectedにします。

class UserService
{
    public function register(): void
    {
        $this->validate();
        $this->save();
    }

    private function validate(): void
    {
    }

    private function save(): void
    {
    }
}

外部へ公開するメソッドを限定すると、クラスの使い方が分かりやすくなります。

また、内部実装を変更しても、外部コードへの影響を抑えやすくなります。

オーバーライドとオーバーロードの違い

オーバーライド

オーバーライドは、親クラスのメソッドを子クラス側で再定義することです。

class Animal
{
    public function speak(): string
    {
        return '鳴き声';
    }
}

class Dog extends Animal
{
    public function speak(): string
    {
        return 'ワン';
    }
}

PHPでは同名メソッドを複数定義できない

Javaなどの言語では、引数の数や型が異なる同名メソッドを複数定義できます。

PHPでは、同じクラス内に同名メソッドを複数定義することは基本的にできません。

class Calculator
{
    public function add(
        int $a,
        int $b
    ): int {
        return $a + $b;
    }

    public function add(
        int $a,
        int $b,
        int $c
    ): int {
        return $a + $b + $c;
    }
}

このコードは、同じadd()メソッドが重複しているためエラーになります。

PHPで「オーバーロード」という言葉が使われる場合、__get()__set()__call()などを利用した動的な処理を指すことがあります。

他のプログラミング言語におけるメソッドオーバーロードとは意味が異なるため、注意が必要です。

PHPのバージョンによる違い

クラスメソッドに関連する機能は、PHPのバージョンによって利用できる範囲が異なります。

機能対応バージョン
スカラー型宣言PHP 7.0以降
戻り値型宣言PHP 7.0以降
nullable型PHP 7.1以降
型付きプロパティPHP 7.4以降
union型PHP 8.0以降
名前付き引数PHP 8.0以降
コンストラクタプロパティプロモーションPHP 8.0以降
mixedPHP 8.0以降
戻り値型のstaticPHP 8.0以降
intersection型PHP 8.1以降
プロパティフックPHP 8.4以降

利用しているPHPのバージョンが古い場合、一部のコードは動作しません。

実行環境のPHPバージョンを確認したうえで、使用する構文を選ぶ必要があります。

PHPのクラスメソッドでよくあるエラー

->::を混同する

インスタンスメソッドは、->で呼び出します。

$user->getName();

staticメソッドは、::で呼び出します。

User::create();

staticメソッドで$thisを使う

次のコードは正しくありません。

public static function getName(): string
{
    return $this->name;
}

staticメソッドには、現在のオブジェクトを表す$thisが存在しないためです。

privateメソッドを外部から呼ぶ

class User
{
    private function validate(): void
    {
    }
}

$user = new User();

$user->validate();

このコードはアクセスエラーになります。

戻り値の型と実際の値が異なる

public function getPrice(): int
{
    return '1000円';
}

戻り値型がintなのに、文字列を返しています。

数値を返す場合は、次のように修正します。

public function getPrice(): int
{
    return 1000;
}

表示用の文字列を返す場合は、戻り値型をstringにします。

public function getFormattedPrice(): string
{
    return '1,000円';
}

PHPのクラスメソッドのまとめ

PHPでは、クラスの中に定義された関数をメソッドと呼びます。

インスタンスメソッドは、オブジェクトを生成して->で呼び出します。

class User
{
    public function greet(): string
    {
        return 'こんにちは';
    }
}

$user = new User();

echo $user->greet();

staticメソッドは、オブジェクトを生成せず、クラス名と::を使って呼び出します。

class Calculator
{
    public static function add(
        int $a,
        int $b
    ): int {
        return $a + $b;
    }
}

echo Calculator::add(10, 20);

クラスメソッドを理解するうえでは、次のポイントが重要です。

  • インスタンスメソッドとstaticメソッドを使い分ける
  • $thisが現在のオブジェクトを表すことを理解する
  • publicprotectedprivateを適切に設定する
  • 引数型と戻り値型を指定する
  • strict_typesの影響を理解する
  • コンストラクタで初期状態を整える
  • 継承時のオーバーライド規則を守る
  • self::static::parent::を使い分ける
  • メソッドとクラスの責務を分ける
  • SQLへ値を直接埋め込まない
  • PHPの対応バージョンを確認する

最初は、$thisを使う通常のインスタンスメソッドから学び、その後にstaticメソッド、継承、抽象クラス、インターフェースへ進むと理解しやすくなります。

以上、PHPのクラスメソッドについてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次