Kintarou'sBlog

プログラミング学習中。学習内容のアウトプットや読書で学んだことなど随時投稿!

【PHP】インターフェースとトレイト

こんにちは😊Kintarouです。

現在エンジニア転職を目指してプログラミング学習中です👨‍🎓
夢はフリーランスエンジニアになって働く人にとって働く事が楽しくなるシステムを作ること!
と、愛する妻と海外移住すること🗽

プログラミングや読んでいる本のことなど、ブログに書いていきます!
twitter : https://twitter.com/ryosuke_angry


今回参考にさせて頂いたサイト様🙇‍♂️ dotinstall.com


インターフェースとは

抽象メソッドのみを持ち、継承関係を無視していくつでもクラスに実装する事ができる。実装したクラスにはインターフェースの型が継承される。

一度フォロワーを増やすfollow機能をインターフェースで実装してみます。

<?php

#interface として記述する。
interface followInterface
{
  public function follow();
}


abstract class BaseUser
{
  protected $name;

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

  abstract public function profile();
}

class TestUser extends BaseUser implements followInterface
{
  private $pattern;

  #followerを初期値0で設定し、followメソッドでfollowerを1増やす定義をする。
  private $follower = 0;

  public function follow()
{
  $this->follower++;
}

  public function __construct($name, $pattern)
  {
    parent::__construct($name);
    $this->pattern = $pattern;
  }

  #profileメソッドでfollower数も表示させる。
  public function profile()
  {
    printf('%s(%s)(%d)' . PHP_EOL, $this->name, $this->pattern, $this->follower);
  }
}

class ProductUser extends BaseUser implements followInterface
{
  private $age;
  #followerを初期値0で設定し、followメソッドでfollowerを1増やす定義をする。
  private $follower = 0;

  public function follow()
{
  $this->follower++;
}

  public function __construct($name, $age)
  {
    parent::__construct($name);
    $this->age = $age;
  }

  #profileメソッドでfollower数も表示させる。
  public function profile()
  {
    printf('%s(%d)(%d)' . PHP_EOL, $this->name, $this->age, $this->follower);
  }
}

$users = [];
$users[0] = new TestUser('Testarou', 'first-pattern');
$users[1] = new ProductUser('Productarou', 30);

#followメソッドを実行する。
$users[0]->follow();
$users[1]->follow();

function profileBaseUser(BaseUser $user)
{
  $user->profile();
}

foreach($users as $user) {
  profileBaseUser($user);
}

#follower数が表示されています。
#=>Testarou(first-pattern)(1)
#=>Productarou(30)(1)

続いて、トレイトについてです。

トレイトとは

メソッドのコードを記述し、クラスに引用する事ができる。トレイトは型ではないので継承されない。

今回は$followerとfollowメソッドの記述をfollowTraitとして記述します。

<?php

#trait として記述する。
trait followTrait
{
    private $follower = 0;

  public function follow()
{
  $this->follower++;
}

}

interface followInterface
{
  public function follow();
}


abstract class BaseUser
{
  protected $name;

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

  abstract public function profile();
}

class TestUser extends BaseUser implements followInterface
{
  private $pattern;
#use followTraitとして、トレイトを実装する。
  use followTrait;

  public function __construct($name, $pattern)
  {
    parent::__construct($name);
    $this->pattern = $pattern;
  }

  #profileメソッドでfollower数も表示させる。
  public function profile()
  {
    printf('%s(%s)(%d)' . PHP_EOL, $this->name, $this->pattern, $this->follower);
  }
}

class ProductUser extends BaseUser implements followInterface
{
  private $age;

#use followTraitとして、トレイトを実装する。
  use followTrait;

  public function __construct($name, $age)
  {
    parent::__construct($name);
    $this->age = $age;
  }

  #profileメソッドでfollower数も表示させる。
  public function profile()
  {
    printf('%s(%d)(%d)' . PHP_EOL, $this->name, $this->age, $this->follower);
  }
}

$users = [];
$users[0] = new TestUser('Testarou', 'first-pattern');
$users[1] = new ProductUser('Productarou', 30);

#followメソッドを実行する。
$users[0]->follow();
$users[1]->follow();

function profileBaseUser(BaseUser $user)
{
  $user->profile();
}

foreach($users as $user) {
  profileBaseUser($user);
}

#follower数が表示されています。
#=>Testarou(first-pattern)(1)
#=>Productarou(30)(1)

以上、どなたかの参考になれば幸いです😊

【PHP】クラスの抽象化

こんにちは😊Kintarouです。

現在エンジニア転職を目指してプログラミング学習中です👨‍🎓
夢はフリーランスエンジニアになって働く人にとって働く事が楽しくなるシステムを作ること!
と、愛する妻と海外移住すること🗽

プログラミングや読んでいる本のことなど、ブログに書いていきます!
twitter : https://twitter.com/ryosuke_angry


今回参考にさせて頂いたサイト様🙇‍♂️ dotinstall.com


子クラスの定義化を強制する

親クラスUserではインスタンスを生成させず、子クラスを作る事を前提としたい場合を考えましょう。
Userクラスをabstract class BaseUserとする事で、インスタンスの生成が出来ない「抽象クラス」にする事が出来ます。(abstract = 概要)

<?php

#abstractとする事で抽象クラスを作ります。
abstract class BaseUser
{
  protected $name;

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

  #こちらもabstractとすることで抽象メソッドとなっています。
  abstract public function profile();
}

class TestUser extends BaseUser
{
  private $pattern;

  public function __construct($name, $pattern)
  {
    parent::__construct($name);
    $this->pattern = $pattern;
  }

  public function profile()
  {
    printf('%s(%s)' . PHP_EOL, $this->name, $this->pattern);
  }
}

$users = [];
$users[0] = new TestUser('Testarou', 'first-pattern');

#TestUser内でprofileメソッドが定義化されているので実行できます。
$users[0]->profile();
#=>Testarou(first-pattern)

※ただ、こうなると元のBaseUserクラス自体がいらないのでは?という疑念が湧きます。
が、抽象クラスのメリットはメソッド名や処理を共通化出来るなど、開発にルールを設ける事ができる事です。
複数人で開発する際には、利用を検討しましょう。

同じ抽象クラスでインスタンスの処理を共通化する

抽象クラスを使い、共通化した場合の利用例です。
TestUserとは別に、本番で利用するProductUserでもインスタンスを作成します。
その後、別のクラスのインスタンスですが共通の動き(profileメソッド)が出来る事を検証します。

<?php

abstract class BaseUser
{
  protected $name;

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

  abstract public function profile();
}

class TestUser extends BaseUser
{
  private $pattern;

  public function __construct($name, $pattern)
  {
    parent::__construct($name);
    $this->pattern = $pattern;
  }

  public function profile()
  {
    printf('%s(%s)' . PHP_EOL, $this->name, $this->pattern);
  }
}

#ProductUserを作ります。
class ProductUser extends BaseUser
{
  private $age;

  public function __construct($name, $age)
  {
    parent::__construct($name);
    $this->age = $age;
  }

  public function profile()
  {
    printf('%s(%d)' . PHP_EOL, $this->name, $this->age);
  }
}

#$usersにTestUser、ProductUserから生成したインスタンスを格納します。
$users = [];
$users[0] = new TestUser('Testarou', 'first-pattern');
$users[1] = new ProductUser('Productarou', 30);

#どちらもBaseUserから型を継承しているので、BaseUser型の$userに対して処理を実行する関数を定義します。
function profileBaseUser(BaseUser $user)
{
  $user->profile();
}

#$usersの要素にforeachでprofileBaseUser(profile)メソッドを実行します。
foreach($users as $user) {
  profileBaseUser($user);
}

#同じメソッドでそれぞれのクラスで定義したインスタンスを実行できました。
#=>Testarou(first-pattern)
#=>Productarou(30)

以上、どなたかの参考になれば幸いです😊

【PHP】クラスの継承

こんにちは😊Kintarouです。

現在エンジニア転職を目指してプログラミング学習中です👨‍🎓
夢はフリーランスエンジニアになって働く人にとって働く事が楽しくなるシステムを作ること!
と、愛する妻と海外移住すること🗽

プログラミングや読んでいる本のことなど、ブログに書いていきます!
twitter : https://twitter.com/ryosuke_angry


今回参考にさせて頂いたサイト様🙇‍♂️ dotinstall.com


クラスを継承する

クラスを継承した子クラスを作る事が出来ます。
仮にnameプロパティを持つUserクラスがあったとして、テスト運用のためのTestUserを作るとしましょう。

<?php

#まずは親クラスとなるUserクラスです。nameプロパティを持っています。
class User
{
  private $name;

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

  public function profile()
  {
    printf('%s' . PHP_EOL, $this->name
    );
  }
}

#TestUserという、Userクラスを親にもつ子クラスを作ります。  
#extendsがUserクラスを受け継いでいる事を意味しています。
class TestUser extends User
{

}

#TestUserのインスタンスを生成します。
$users = [];
$users[0] = new TestUser('Testarou');

#TestUserには何も記述していませんが、Userクラスを継承しているのでprofileメソッドも使えます。
$users[0]->profile();
#=>Testarou

子クラス独自のプロパティとメソッドを記述する

上記のTestUserに独自のプロパティやメソッドを記述します。
どのパターンのテストをするのかを識別するpatternプロパティとパターンを表示するpatternShowメソッドを記述します。

<?php

class User
{
  private $name;

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

  public function profile()
  {
    printf('%s' . PHP_EOL, $this->name
    );
  }
}

class TestUser extends User
{
  #$patternプロパティを記述します。
  private $pattern;

  #コンストラクタにて、$nameは親クラスのプロパティなのでparent::__constructで記述します。
  public function __construct($name, $pattern)
  {
    parent::__construct($name);
    $this->pattern = $pattern;
  }

  #patternShowで$patternの内容を出力するメソッドを定義します。
  public function patternShow()
  {
    printf('%s' . PHP_EOL, $this->pattern);
  }
}

$users = [];
$users[0] = new TestUser('Testarou', 'first-pattern');

$users[0]->patternShow();
#=>first-pattern

親クラスのメソッドを再定義する

先ほどのpatternShowメソッドですが、TestUserのインスタンスの場合親クラスのprofileメソッドで$nameと一緒に出力した方が、メソッドもまとめられて便利そうです。
そうしたい場合にメソッドのオーバーライド(override)というのが使えます。

<?php

class User
{
  #子クラスでも使えるようにするためアクセス修飾子をprotectedにします。
  protected $name;

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

  public function profile()
  {
    printf('%s' . PHP_EOL, $this->name
    );
  }
}

class TestUser extends User
{
  private $pattern;

  public function __construct($name, $pattern)
  {
    parent::__construct($name);
    $this->pattern = $pattern;
  }

  #nameも追加した同名(profile)メソッドをoverrideします。
  #nameプロパティも$this->nameで記述します。
  public function profile()
  {
    printf('%s(%s)' . PHP_EOL, $this->name, $this->pattern);
  }
}

$users = [];
$users[0] = new TestUser('Testarou', 'first-pattern');

#profileメソッドで$patternも出力されています。
$users[0]->profile();
#=>Testarou(first-pattern)

※仮に継承後の子クラスでoverrideして欲しくないとなった場合には、メソッドのアクセス修飾子の前にfinalを付けるとその後のoverrideを制限できます。

以上、どなたかの参考になれば幸いです😊

【PHP】クラスプロパティ・クラスメソッド・オブジェクト定数の設定

こんにちは😊Kintarouです。

現在エンジニア転職を目指してTECH CAMPにてプログラミング学習中です👨‍🎓
夢はフリーランスエンジニアになって働く人が働きやすいシステムを作ること!
と、愛する妻と海外移住すること🗽

プログラミングや読んでいる本のことなど、ブログに書いていきます!
twitter : https://twitter.com/ryosuke_angry


今回参考にさせて頂いたサイト様🙇‍♂️ dotinstall.com


クラスのプロパティ、メソッドを設定する

クラスに対するプロパティを設定する場合はstaticを使います。
例として、Userクラスで生成されたインスタンス($users)の名簿を格納する$listsを作ってみます。
メソッドはクラス名::メソッド名で実行出来ます。

<?php

#クラスのプロパティにはstaticをつけます。
class User
{
  private $name;
  private static $lists = [];
  
  #staticのついたプロパティにはself::でアクセスします。

  public function __construct($name)
  {
    $this->name = $name;
    array_push(self::$lists, $this->name);
  }

  public function profile()
  {
    printf('%s' . PHP_EOL, $this->name
    );
  }

  public static function showLists()
  {
    print_r(self::$lists);
  }

}

$users = [];

$users[0] = new User('Kintarou');
$users[1] = new User('Kinjirou');

#staticのついたメソッドはクラス名::で実行します。

User::showLists();

#=>Array
#=>(
#=>    [0] => Kintarou
#=>    [1] => Kinjirou
#=>)

クラスにオブジェクト定数を設定する

クラスに変数ではなく、定数を設定する事もできます。
今回はUserクラスの使い方をHELPという定数で設定します。

<?php

#定数は慣習的に大文字で$はいりません。staticも不要です。
#定数は後で再代入される事がないのでpublicで大丈夫です。
class User
{
  private $name;
  public const HELP = "ユーザーを作成するクラスです。\n引数にはユーザー名を渡します。";

  public function profile()
  {
    printf('%s' . PHP_EOL, $this->name
    );
  }

}


#クラス名::定数名で呼び出せます。
echo User::HELP . PHP_EOL;

#=>ユーザーを作成するクラスです。
#=>引数にはユーザー名を渡します。

以上、どなたかの参考になれば幸いです😊

【PHP】アクセス修飾子でクラスに制限をかける

こんにちは😊Kintarouです。

現在エンジニア転職を目指してTECH CAMPにてプログラミング学習中です👨‍🎓
夢はフリーランスエンジニアになって働く人が働きやすいシステムを作ること!
と、愛する妻と海外移住すること🗽

プログラミングや読んでいる本のことなど、ブログに書いていきます!
twitter : https://twitter.com/ryosuke_angry


今回参考にさせて頂いたサイト様🙇‍♂️
dotinstall.com


アクセス修飾子とは

クラス内の変数やメソッドがどこからアクセス出来るようにするかを指定するものです。
何も表記が無いとpublicとなります。

アクセス修飾子 アクセス権限
public どこからでもアクセス可能
private 同じクラス内のみアクセス可能
public 同じクラス・子クラスのみアクセス可能

privateやpublicは、アクセスに制限をかけるイメージです。
なぜ制限をする必要があるかというと、クラス外の操作で意図せぬ動作を起こさないようにするためです。

昨日の記事と同じUserクラスを使って例を出します。

<?php

class User
{
  #followerは最初0で、フォローされる事に1ずつ増えるという動きしか想定しません。
  public $name;
  public $age;
  public $follower = 0;
  
  public function __construct($name, $age)
  {
    $this->name = $name;
    $this->age = $age;
  }

  public function profile()
  {
    printf('%s (%d)(%d)' . PHP_EOL, $this->name, $this->age, $this->follower
    );
  }
}

$users = [];

$users[0] = new User('Kintarou', 30);
$users[1] = new User('Kinjirou', 35);

#通常はこの動作で1ずつ増やす事しか想定していません。
$users[0]->follower++;

$users[0]->profile();
#=>Kintarou (30)(1)

#制限が無いと意図しない数字になる恐れがあります。
$status = -15;
$users[1]->follower = $status;

$users[1]->profile();
#=>Kinjirou (35)(-15)

上記のように、$followerをクラス外で操作されると意図しない動作をする可能性があります。

privateで制限をかける

この場合、$followerのアクセス権限をクラス内のみにしてfollower++のメソッドもクラス内に記述します。

<?php

class User
{
  #$followerをprivateにする事でクラス外で直接アクセスする事を制限します。
  public $name;
  public $age;
  private $follower = 0;
  
  public function __construct($name, $age)
  {
    $this->name = $name;
    $this->age = $age;
  }

  public function profile()
  {
    printf('%s (%d)(%d)' . PHP_EOL, $this->name, $this->age, $this->follower
    );
  }

  #$followerを1ずつ増やす動作をfollowメソッドとします。
  public function follow()
  {
    $this->follower++;
  }
}

$users = [];

$users[0] = new User('Kintarou', 30);
$users[1] = new User('Kinjirou', 35);

#followメソッドでfollowerを1増やします。
$users[0]->follow();

$users[0]->profile();
#=>Kintarou (30)(1)

#アクセス権限のある変数に直接アクセスしようとするとエラーとなります。
$status = -15;
$users[1]->follower = $status;

$users[1]->profile();
#=>Fatal error: Uncaught Error: Cannot access private property User::$follower in /home/dotinstall/main.php:41...

以上、どなたかの参考になれば幸いです😊

【PHP】クラスとインスタンスの作成

こんにちは😊Kintarouです。

現在エンジニア転職を目指してTECH CAMPにてプログラミング学習中です👨‍🎓
夢はフリーランスエンジニアになって働く人が働きやすいシステムを作ること!
と、愛する妻と海外移住すること🗽

プログラミングや読んでいる本のことなど、ブログに書いていきます!
twitter : https://twitter.com/ryosuke_angry


今回参考にさせて頂いたサイト様🙇‍♂️
dotinstall.com


クラスを作る

変数や関数が定義された"クラス"を作る方法をまとめます。
まずは$usersに名前(name)と年齢(age)、SNSアプリを仮定してフォロワー(Follower)を持った配列を作りましょう。

<?php

$users = [];
$users[0] = ['name' => 'Kintarou', 'age' => 30, 'follower' => 0];
$users[1] = ['name' => 'Kinjirou', 'age' => 35, 'follower' => 0];

#ユーザーを紹介するprofile関数も作りましょう。
function profile($user)
{
  printf('%s (%d)(%d)' . PHP_EOL, $user['name'], $user['age'], $user['follower']);
}

profile($users[0]);
#=>Kintarou (30)(0)

profile($users[1]);
#=>Kinjirou (35)(0)

この変数と関数を併せてまとめたいとなった場合にクラスが使えます。
クラスを使って同じ表現をしていきます。

<?php

class User
{
  #publicというアクセス修飾子で、どこでも使えるものにします。
  public $name;
  public $age;
  public $follower;

  #$thisという擬似変数でインスタンスの変数を使う事を指しています。
  public function profile()
  {
     printf('%s (%d)(%d)' . PHP_EOL, $this->name, $this->age, $this->follower);
}
  }


#以上がクラスの構造です。以下、クラスを使ったインスタンスを作成します。

$users = [];

$users[0] = new User();
$users[0]->name = 'Kintarou';
$users[0]->age = 30;
$users[0]->follower = 0;

$users[1] = new User();
$users[1]->name = 'Kinjirou';
$users[1]->age = 35;
$users[1]->follower = 0;

#クラスに設定した関数(メソッド)を使います。

$users[0]->profile();
#=>Kintarou (30)(0)

$users[1]->profile();
#=>Kinjirou (35)(0)

コンストラクタで簡易にインスタンスを作る

constructというメソッドを使い、new()に引数を渡してインスタンスを作成します。

<?php

class User
{
  public $name;
  public $age;
  public $follower;
  
  #ここにコンストラクタを記述します。アンダーバー2つを繋げて__constructとします。
  public function __construct($name, $age, $follower)
  {
    $this->name = $name;
    $this->age = $age;
    $this->follower = $follower;
  }

  public function profile()
  {
    printf('%s (%d)(%d)' . PHP_EOL, $this->name, $this->age, $this->follower
    );
  }
}

#コンストラクタを設定したので引数に要素を渡せば同じインスタンスを生成できます。

$users = [];

$users[0] = new User('Kintarou', 30, 0);

$users[1] = new User('Kinjirou', 35, 0);

$users[0]->profile();
#=>Kintarou (30)(0)

$users[1]->profile();
#=>Kinjirou (35)(0)

インスタンスの要素の初期値を設定する

インスタンス生成時はfollowerは0となるので、最初から初期値を0として設定します。

<?php

class User
{
  #followerに0を代入しておきます。
  public $name;
  public $age;
  public $follower = 0;
  
  #followerはコンストラクタで設定する必要が無くなります。
  public function __construct($name, $age)
  {
    $this->name = $name;
    $this->age = $age;
  }

  public function profile()
  {
    printf('%s (%d)(%d)' . PHP_EOL, $this->name, $this->age, $this->follower
    );
  }
}

$users = [];

#引数にも渡す必要が無くなります。
$users[0] = new User('Kintarou', 30);
$users[1] = new User('Kinjirou', 35);

$users[0]->profile();
#=>Kintarou (30)(0)

$users[1]->profile();
#=>Kinjirou (35)(0)

以上、どなたかの参考になれば幸いです😊

【PHP】ディレクトリを操作する・ファイルの存在確認の関数

こんにちは😊Kintarouです。

現在エンジニア転職を目指してTECH CAMPにてプログラミング学習中です👨‍🎓
夢はフリーランスエンジニアになって働く人が働きやすいシステムを作ること!
と、愛する妻と海外移住すること🗽

プログラミングや読んでいる本のことなど、ブログに書いていきます!
twitter : https://twitter.com/ryosuke_angry


今回参考にさせて頂いたサイト様🙇‍♂️
dotinstall.com


ディレクトリを操作する

ディレクトリにあるファイルの内容を取得します。
ディレクトリを取得するのにopendir、ディレクトリ内のファイルを読み込むのにreaddirを使います。

<?php

#file_put_contentsを用いて事前に作成しておいたdataディレクトリに下記のファイルを作成します。
file_put_contents('data/text1.txt', "text1\n");
file_put_contents('data/text2.txt', "text2\n");

#opendirでdataファイルを取得し、readdirを用いて先ほど作成したファイルを読み込みます。
#読み込むファイルが無くなったらfalseを返すのでwhileでtrueの間は読み込みます。
#ディレクトリをあらわすドットが読み込まれるのですが不要なのでcontinueでスキップします。
$dp = opendir('data');
while (($item = readdir($dp)) !== false) {
  if ($item === '.' || $item === '..'){
    continue;
  }
  echo $item . PHP_EOL;
}

#=>text2.txt
#=>text1.txt


#上記の内容をglob関数を使うことで同じ動作ができます。
#ワイルドカードを使って当てはまるファイルを配列要素として読み込めます。
#

foreach (glob('data/*.txt')as $item) {
  echo basename($item) . PHP_EOL;
}

#=>text1.txt
#=>text2.txt

ディレクトリやファイルのチェックを行う

以下で、ファイルが存在しているか、書き込み、読み込み可能かをチェックできます。

関数名 処理内容
file_exists 指定したファイルが存在するかを真偽値で返す
is_writable 指定したファイルが書き込み可能かを真偽値で返す
is_readable 指定したファイルが読み込み可能かを真偽値で返す
<?php

#上記で作成したdataディレクトリの存在確認をします。
if(file_exists('data') === true) {
  echo 'data exists!' . PHP_EOL;
}

#=>data exists!

#dataディレクトリの中のtext1.txtが書き込み可能かを確認します。
if(is_writable('data/text1.txt') === true) {
  echo 'text1 is writable!' . PHP_EOL;
}

#=>text1 is writable!

#dataディレクトリの中のtext2.txtが読み込み可能かを確認します。
if(is_readable('data/text2.txt') === true) {
  echo 'text2 is readable!' . PHP_EOL;
}

#=>text2 is readable!

以上、どなたかの参考になれば幸いです😊