20200516のPHPに関する記事は16件です。

無名クラス/ただのクラス/abstractクラス/finalクラス/インターフェース/トレイトを使う/使われる

はじめに

PHPにはクラスもしくはクラスっぽいものがいろいろあります。また、これらのクラスやクラスっぽいものたちはお互いに使ったり使われたりしています。

使う/使われるの組み合わせでどれがOKでどれがNGなのか気になったのでひたすら実験するのがこの記事です。なおOK/NGはクラスやクラスっぽいものの中身の定数/プロパティ/メソッドなどにも依存すると思いますが、この記事では中身は空っぽにして表面だけに注目することにします。

使われる側

使われる側
// 無名クラス
$object = new class {};

// ただのクラス
class TadanoClass {}

// abstractクラス
abstract class AbstractClass {}

// finalクラス
final class FinalClass {}

// ただのインターフェース
interface TadanoInterface {}

// ただのトレイト
trait TadanoTrait {}

使う側

使う側
// 無名クラス
$object = new class {};

// ただのクラス再び
class AnotherTadanoClass {}

// abstractクラス再び
abstract class AnotherAbstractClass {}

// finalクラス再び
final class AnotherFinalClass {}

// ただのインターフェース再び
interface AnotherTadanoInterface {}

// ただのトレイト再び
trait AnotherTadanoTrait {}

無名クラスが使う側

無名クラスが使う側
// 無名クラスを使いたい
$object = new class extends class {} {};
// => PHP Parse error:  syntax error, unexpected 'class' (T_CLASS), expecting identifier (T_STRING) or namespace (T_NAMESPACE) or \\ (T_NS_SEPARATOR)

// ただのクラスを使いたい
$object = new class extends TadanoClass {};

// abstractクラスを使いたい
$object = new class extends AbstractClass {};

// finalクラスを使いたい
$object = new class extends FinalClass {};
// => PHP Fatal error:  Class class@anonymous may not inherit from final class (FinalClass)

// ただのインターフェースを使いたい
$object = new class implements TadanoInterface {};

// ただのトレイトを使いたい
$object = new class { use TadanoTrait; };

ただのクラスが使う側

ただのクラスが使う側
// 無名クラスを使いたい
class AnotherTadanoClass extends class {} {};
// => PHP Parse error:  syntax error, unexpected 'class' (T_CLASS), expecting identifier (T_STRING) or namespace (T_NAMESPACE) or \\ (T_NS_SEPARATOR)

// ただのクラスを使いたい
class AnotherTadanoClass extends TadanoClass {};

// abstractクラスを使いたい
class AnotherTadanoClass extends AbstractClass {};

// finalクラスを使いたい
class AnotherTadanoClass extends FinalClass {};
// => PHP Fatal error:  Class AnotherTadanoClass may not inherit from final class (FinalClass)

// ただのインターフェースを使いたい
class AnotherTadanoClass implements TadanoInterface {};

// ただのトレイトを使いたい
class AnotherTadanoClass { use TadanoTrait; };

abstractクラスが使う側

abstractクラスが使う側
// 無名クラスを使いたい
class AnotherAbstractClass extends class {} {};
// => PHP Parse error:  syntax error, unexpected 'class' (T_CLASS), expecting identifier (T_STRING) or namespace (T_NAMESPACE) or \\ (T_NS_SEPARATOR)

// ただのクラスを使いたい
class AnotherAbstractClass extends TadanoClass {};

// abstractクラスを使いたい
class AnotherAbstractClass extends AbstractClass {};

// finalクラスを使いたい
class AnotherAbstractClass extends FinalClass {};
// => PHP Fatal error:  Class AnotherAbstractClass may not inherit from final class (FinalClass)

// ただのインターフェースを使いたい
class AnotherAbstractClass implements TadanoInterface {};

// ただのトレイトを使いたい
class AnotherAbstractClass { use TadanoTrait; };

finalクラスが使う側

finalクラスが使う側
// 無名クラスを使いたい
class AnotherFinalClass extends class {} {};
// => PHP Parse error:  syntax error, unexpected 'class' (T_CLASS), expecting identifier (T_STRING) or namespace (T_NAMESPACE) or \\ (T_NS_SEPARATOR)

// ただのクラスを使いたい
class AnotherFinalClass extends TadanoClass {};

// abstractクラスを使いたい
class AnotherFinalClass extends AbstractClass {};

// finalクラスを使いたい
class AnotherFinalClass extends FinalClass {};
// => PHP Fatal error:  Class AnotherFinalClass may not inherit from final class (FinalClass)

// ただのインターフェースを使いたい
class AnotherFinalClass implements TadanoInterface {};

// ただのトレイトを使いたい
class AnotherFinalClass { use TadanoTrait; };

ただのインターフェースが使う側

ただのインターフェースが使う側
// ただのインターフェースを使いたい
interface AnotherTadanoInterface extends TadanoInterface {};

// ただのトレイトを使いたい
interface AnotherTadanoInterface { use TadanoTrait; };
// => PHP Fatal error:  Cannot use traits inside of interfaces. TadanoTrait is used in AnotherTadanoInterface

ただのトレイトが使う側

ただのトレイトが使う側
// ただのトレイトを使いたい
trait AnotherTadanoTrait { use TadanoTrait; };

おわりに

長部に合ったやり方で理解することが叶いました。みんながみんなこのやり方がわかりやすいかと言えばおそらくそうではないでしょう。もし似たような理解の仕方をするかたがいらしゃったらお声がけいただけると喜びます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Guzzleを使って外部APIへPOST送信

Guzzleとは

PHP用のHTTPクライアントライブラリです。
WEBサーバに外部APIへPOST送信などを行いたい際にGuzzleが非常に便利でした。

導入方法・簡単な使い方をまとめてみました。

インストール方法

composerコマンドでguzzlehttp/guzzleパッケージのインストール

composer require guzzlehttp/guzzle

2020年5月現在、最新は6.5のようです。

composer.json
{
    "require": {
        "guzzlehttp/guzzle": "^6.5"
    }
}

使い方

app/src/Controller/Front/ApiController.php
use GuzzleHttp\Client;

public function getSession()
{
    $session = $this->request->getSession(); //セッションを取得
    $data = $session->read('data');          //Formで入力しているデータを取得します

    $this->postApi($data); 
    //略
}

public function postApi($data)
{
    $url         = "https://external.api";                  //API側(受取側)のURLを指定
    $basic       = "basic-id:basic-password"                //basic認証のIDとPASSWORD ※envに格納しましょう
    $encodeBasic = base64_encode($basic);                   //basic認証をエンコーディング
    $config      = ['base_uri' => 'https://www.this.com/']; //送信元のURLを指定

    $client = new Client($config);

            $option = [
            'http_errors' => true,                             //エラーを出力
            'verify'      => false,                            //SSL認証を無視

            'headers' =>    //ヘッダーにBASIC認証などを追加
            [                                     
                'Authorization' => 'Basic ' . $encodeBasic,    //エンコードしたbasic認証です。外部API側でデコードしてください
                'Host'          => "external.api",             //外部APIのホスト指定
                'Content-Type'  => "text/plain",               //コンテントタイプを指定 無くてもできました。
            ],

            'form_params' => //application / x-www-form-urlencoded POSTリクエストを送信するために使用
            [
                "username"      => $data["name"],      //外部APIとカラム名が異なっていたのでここで修正。
                "tel"           => $data["telephone"], //同上
                "address"       => $data["mail"],      //同上
                "contents"      => $data["content"],   //同上
            ],
        ];

    $response = $client->request("POST", $url, $option); //第1引数はPOST or GET、第2引数は受取側のAPI,第3引数はPOST送信データ
}

レスポンスのステータスコードのチェック

app/src/Controller/Front/ApiController.php
    $response->getStatusCode(); 

参考にした資料

Guzzleドキュメント
http://docs.guzzlephp.org/en/stable/index.html

Guzzle Httpを試してみたよ clustfe様
https://qiita.com/clustfe/items/f9ff2b12da7a501197f8

Guzzleでファイルアップロードする zaburo様
https://qiita.com/yousan/items/2a4d9eac82c77be8ba8b

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Lraravelヘルパ関数の配列とオブジェクトについて

はじめに

今回はLraravelヘルパ関数の配列とオブジェクトについてまとめます。

連想配列の関数について(抜粋)

Arrクラスは配列を操作する時に便利に使えます。

①Arr::addメソッドは指定キー/値のペアをそのキーが存在していない場合とnullがセットされている場合に、配列に追加します。

use Illuminate\Support\Arr;
$array = Arr::add(['name' => 'skirt'], 'price', 5000);
// ['name' => 'Desk', 'price' => 5000]
$array = Arr::add(['name' => 'skirt', 'price' => null], 'price', 5000);
// ['name' => 'Desk', 'price' => 5000]

②Arr::getメソッドは「ドット」記法で指定した値を深くネストされた配列から取得します。

use Illuminate\Support\Arr;
$array = ['products' => ['skirt' => ['price' => 5000]]];
$price = Arr::get($array, 'products.skirt.price');
// 5000

③Arr::forgetメソッドは「ドット記法」で指定キー/値のペアを深くネストされた配列から取り除きます。

use Illuminate\Support\Arr;
$array = ['products' => ['skirt' => ['price' => 5000]]];
Arr::forget($array, 'products.skirt');
// ['products' => []]

終わりに

いかがでしたでしょうか。
よく使いそうなものを抜粋しましたが公式ドキュメントに他にも記載してあるので確認してみてください。

参考:ヘルパ 7.x Laravel

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP】生成したインスタンスの数をカウントする方法

【PHP】生成したインスタンスの数をカウントする方法

初期値0の変数を用意し、インスタンス生成毎に1足していく。

▼使うもの
- クラスプロパティ(変数の定義)
- コンストラクタ (インスタンス生成毎に1足す処理)
- クラスメソッド(数値の取得)



▼クラス内の記述

$count:インスタンスの数を入れる変数
$count++: \$count = $count + 1
getCount(): インスタンスの数を取得するメソッド
*変数名、メソッド名は任意

class クラス名{
    //クラスプロパティを定義(初期値0)
    protected static $count = 0;

    // コンストラクタを定義
    public function __construct(){

        // インスタンス生成時に1を足す
        self::$count++;
    }

    // クラスメソッドを定義
    public static function getCount(){
        return self::$count;
    }
}



▼クラス外で呼び出し

<?php echo クラス名::getCount() ?>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP】生成したインスタンスの数をカウントする方法(idの設定方法)

【PHP】生成したインスタンスの数をカウントする方法(idの設定方法)

初期値0の変数を用意し、インスタンス生成毎に1足していく。

▼使うもの
- クラスプロパティ(変数の定義)
- コンストラクタ (インスタンス生成毎に1足す処理)
- クラスメソッド(数値の取得)



▼クラス内の記述

$count:インスタンスの数を入れる変数
$count++: \$count = $count + 1
getCount(): インスタンスの数を取得するメソッド
*変数名、メソッド名は任意

class クラス名{
    //クラスプロパティを定義(初期値0)
    protected static $count = 0;

    // コンストラクタを定義
    public function __construct(){

        // インスタンス生成時に1を足す
        self::$count++;
    }

    // クラスメソッドを定義
    public static function getCount(){
        return self::$count;
    }
}



▼クラス外で呼び出し

<?php echo クラス名::getCount() ?>


id番号の設定

上記を応用して固有なidの設定も可能。

▼使うもの
- クラスプロパティ(変数の定義)
- コンストラクタ (インスタンス生成毎に1足す処理)
- クラスメソッド(数値の取得)
- idを入れるプロパティ(インスタンス毎)



▼書き方

  • インスタンスを生成する毎に、$count(クラスプロパティ)に1を足す。
  • 次のインスタンスが生成される前にプロパティ(id)にその値をセット。
  • 設定したid取得用にゲッター「getId()」をセット
class User{

    private $id;
    private static $count=0;

    public function __construct(){
        //idの設定
        self::$count++;
        $this->id = self::$count;
    }

    public function getId(){
        return $this->id;
    }
}

▼クラス外で呼び出し
インスタンス->getId()

userAというインスタンスの場合

//インスタンスの生成
<?php $userA = new User() ?>

//id番号の取得
<?php echo userA->getId() ?>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Geniusで歌詞を取ってくる方法

はじめに

現在作成中のアプリで、歌詞を取ってくる機能を実装したいと思い
そのようなAPIがないのか探したところGeniusと言うAPIが存在することを
知りました。
ですが、日本語での解説記事に全然巡り合えなかったので、今回は
Geniusの使い方を記載させてもらえたらと思います。
以下Geniusの使い方、また詰まったところを解説します。
※デモgifです
キータgenius.gif

詰まった点

英語のドキュメントしか巡り合えなかったため、英文を読む or Google翻訳なりで
訳して理解するかのどちらかだと思うが、自分は前者を採用して頑張って
英文を理解することにした。
難しい英文ではなかった事と、ドキュメントのAPI使用法の解説が丁寧であった
事から一応読めた。
ドキュメントを読むうちにこの英文はこういう意味では?と思ってコードを書いても
実際は全然理解が違ったりしたのが詰まった点。
全く関係ないライブラリをダウンロードして実装していたりとドキュメントの意味を
間違えてかなり時間を食ってしまった。
逆に言うと、英語を難なく理解できる人であればたやすく利用できるのではないのか?
と感じた。
やはり英語が出来るのは強いと感じた。
あと、自分が参考にしたのは100%公式のドキュメントだった。
公式ドキュメントは何と言ってもそのAPIを作成した人たちが書いているので、
一番強いと思っている。

使用法

まず、Geniusのページ(https://genius.com/developers)
に飛んでサインアップして自分の作成するアプリを登録して
CRIENT_ID,CRIENT_SECRET,CRIENT_ACCESS_TOKENの3つを取得します。
※歌詞を取得する際に使うのはCRIENT_ACCESS_TOKENだけです。

そして、Geniusのアノテーションを作成しているアプリに埋め込みます。
↓こちらがGeniusのアノテーション

sample.php
<script src="https://genius.codes"></script>

アノテーションはmetaタグの次に埋め込むと良いと思います。
そうした後は、composerを使用して
コマンドプロンプトやターミナルでアプリのディレクトリにて
composer require simivar/genius-php php-http/message php-http/guzzle6-adapter
を打ち込んで、Geniusのパッケージをダウンロードします。
Geniusからは、楽曲に関する様々な情報が取得できます。
歌詞以外に関する情報はこちらには記載しないので、公式ドキュメント
(https://docs.genius.com/#/getting-started-h1)
を参照していただければ、と思います。
実際のコードを載せます。

sample.php
require 'vendor/autoload.php';
  $authentication = new \Http\Message\Authentication\Bearer($_ENV['CLIENT_ACCESS_TOKEN']);
  $genius = new \Genius\Genius($authentication);
  $getSongId = $genius->getSearchResource()->get('lemon 米津')->response->hits[0]->result->id;
  $searchSong = $genius->getSongsResource()->get($getSongId,'html')->response->song>embed_content;

2行目のCLIENT_ACCESS_TOKENには、アプリ登録時にGeniusから送信されたアクセストークンを設定します。
そのあと

$getSongId = $genius->getSearchResource()->get('lemon 米津')->response->hits[0]->result->id;

でget()の中に入れた文字列(ここではヒットしやすいように入れた米津玄氏さんのlemon)をもとに
曲のidを取得しています。
そしてそのidをもとにして、ヒットした歌詞を表示しています。

$searchSong = $genius->getSongsResource()->get($getSongId,'html')->response->song>embed_content;

getの2つ目の引数には、dom,plainそしてhtmlなど様々な引数を代入できますが、
歌詞を取ってくるにはhtmlじゃないとキツそうだったので僕はhtml
を選択しました。

そのあと、取ってき歌詞を表示するためにhtmlを生成してあげればOKです。

<?php print($searchSong);?>

おわりに

外部APIを使用すると段違いに実装できる内容が増えて、よりアプリの利便性を
高めてくれる事を実感しました。
これからも面倒くさがらずに、英語のドキュメントに挑戦して
外部APIを使用していきます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP】クラスの継承・ファイル分割の方法。オーバーライドとは?

【PHP】クラスの継承・ファイル分割の方法。オーバーライドとは?

クラスの継承

既に定義済みのクラスのプロパティやメソッドをまるごと利用して、新たにメソッドやプロパティ追加した、別のクラス名を定義する。

class クラス名 extends 親クラス名{}

//既存のProductクラスを親として、新たにPhoneクラスを定義
class Phone extends Product{

}


ファイル分割

require_once('ファイル名');

//Prodcutクラスが書かれたファイルproduct.phpを読み込む
require_once('product.php')

<分割の用途>
・クラス毎に分割
・インスタンス生成(データ用)
・表示用

ファイル分割の例

▼下記6ファイルの場合
親クラスを定義したファイル
①product.php
②review.php

継承(product.phpの内容)
③phone.php
④watch.php

データファイル(インスタンスの生成)
⑤data.php

表示
⑥index.php

▼ファイル呼び出しの記述
①、②不要

③phone.php、④watch.php
require_once('product.php');
⑤data.php
require_once('phone.php');
require_once('watch.php');
⑥index.php
require_once('data.php');
require_once('review.php');

⑥index.phpでは、①~⑤のすべてのファイルを呼び出していることになる。


オーバーライドとは

継承した子クラスで、親クラスのメソッドを上書きすること。

事例の前に、オーバーライドでよく使われる構文を一つ。
parent::メソッド名();
 └ 親クラスのメソッドの呼び出し



▼オーバーライドの例(コンストラクタ)

①親(Product)クラスのコンストラクタ product.php
class Product{
    // プロパティ
    protected $name;
    protected $price;
    protected $image;
    protected $orderCount=0;

    // コンストラクタ
    public function __construct($name, $price, $img){
        $this->name = $name;
        $this->price = $price;
        $this->image = $img;
    } 
}



上記のProductクラスを継承したPhoneクラスを生成し、コンストラクタをオーバーライドする。

②オーバーライド(コンストラクタの上書き)
<?php 
    //Productクラスの書かれたファイルを読み込み
    require_once('product.php');

    //productクラスを継承し、Phoneクラスを作成
    class Phone extends Product{

        //sizeプロパティを新たに追加
        private $size;

        //コンストラクタをオーバーライド
        public function __construct($name, $price, $img, $size){
            parent::__construct($name, $price, $img);

           //新たに定義したプロパティの値をセット
            $this->size =$size;
        }



parent::__construct($name, $price, $img);は以下と同じ内容(書き換え可能)

$this->name = $name;
$this->price = $price;
$this->image = $img;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP】クラスのアクセス権・プロパティ・メソッドの書き方($this, self::)

【PHP】クラスのアクセス権・プロパティ・メソッドの書き方

クラスを作成するときの書き方のメモ。

  1. クラス
  2. アクセス権
  3. プロパティ
  4. メソッド
  5. ゲッターとセッター
  6. クラスプロパティとクラスメソッド
  7. インスタンス
  8. コンストラクタ
  9. 主な特殊記号($this, ::, self::)

クラス

class [クラス名] {}
 └ クラス名は1文字目が大文字

例(クラス名 Product)
class Product{
   //プロパティやメソッド
}

アクセス権

3種類
▼アクセス権が厳しい順

1.private
・定義したクラス内でのみアクセス可。

2.protected
・継承クラス(子クラス)でもアクセス可

3.public
・クラスの外からアクセス可



privateやprotectedなど外からアクセスできなくすることをカプセル化という。

セキュリティ上、プロパティはカプセル化し、値の取得・変更にはメソッドを使う(ゲッターとセッター)。


プロパティ

[アクセス権] [$プロパティ名];

private $name;
protected $size;
public $color;  



▼プロパティの取得

[インスタンス名]->[プロパティ名]
└ プロパティ名に「$」は不要

//メソッドを呼び出しているインスタンスのnameプロパティにアクセス
$this->name;

//インスタンスを格納した変数(例:appleWatch)のnameプロパティにアクセス
$appleWatch->name;



▼プロパティの値変更

[インスタンス名]->[プロパティ名] = [変更後の値]
└ プロパティ名に「$」は不要

//メソッドを呼び出しているインスタンスのnameプロパティにアクセスし値をiphoneに変更
$this->name = 'iphone'

//インスタンスを格納した変数(例:appleWatch)のnameプロパティにアクセスし値をapple_watch_3に変更
$appleWatch->name = 'apple_watch_3'


メソッド

[アクセス権] function [メソッド名](){}
 └ メソッド名の後ろに「()」をつける
 └ メソッド名は大文字・小文字区別あり
 └ $は不要

//hello worldを出力するhelloメソッド
public function hello(){
   echo 'hello world!';
}

//消費税込みの価格を返すメソッド(引数に価格入れる)
public function taxIncludePrice($price){
   return $price*1.01;
}


ゲッターとセッター

特定の役割をするメソッドの名称

▼ゲッター
 └ カプセル化したプロパティの値を取得
 └ メソッド名の冒頭に「get」をつける
 └ 戻り値(return)にする

▼セッター
 └ カプセル化したプロパティの値を変更
 └ メソッド名の冒頭に「set」をつける
 └ 「=」でプロパティの値を変更する
 └ プロパティをコンストラクタでセットする場合は不要

いずれもクラスの外からアクセスするため、アクセス権はpublicとする。

//ゲーターの例
public getName(){
 return $this->name;
}


//セッターの例
public setName(){
 $this->name = '変更する値';
}


クラスプロパティとクラスメソッド

  • 個々のインスタンスではなく、クラスが持つデータにアクセスする場合に定義する。
  • アクセス権の後に「static」
  • アクセスは「クラス名::」
  • 定義したクラス内で呼び出す場合は「self::」

<使用例>
・生成したインスタンスの数をカウントする。
・すべてのインスタンスの中から、指定した条件に一致するインスタンスを抽出する。


クラスプロパティ

▼クラスプロパティの定義
[アクセス権] static $[プロパティ名]

▼クラスプロパティの取得
[クラス名]::$[プロパティ名]
 └ クラス内で設定する場合、クラス名は「self」になる
 └ 「$」必要。(普通のプロパティと異なる)
 └ アロー「->」が「::」に置き換わる

//クラスプロパティの定義
protected static $count=0;

//クラスプロパティの取得
//クラス内
self::$count;

//クラス外(クラス名Productが持つプロパティにアクセス)
Product::$count;


クラスメソッド

▼クラスメソッドの定義
[アクセス権] static function [メソッド名](){}

▼クラスメソッドの呼び出し
[クラス名]::[メソッド名](){}
 └ クラス内で設定する場合、クラス名は「self」になる
 └ 「$」必要。(普通のプロパティと異なる)
 └ アロー「->」が「::」に置き換わる

//クラスメソッドの定義
protected static function getCount(){
 //処理
};

//クラスメソッドの呼び出し
//クラス内
self::getCount();

//クラス外(クラス名Productが持つクラスメソッドの呼び出し)
Product::getCount();


インスタンスの生成

$変数名 = new クラス名()
└ new:インスタンスの生成
└ 生成したインスタンスを変数に格納

$appleWatch = new Product();


コンストラクタ

public function __construct(){}

・インスタンス生成時に自動で呼び出されるメソッド
・プロパティのセットで使用
・生成したインスタンスの数をカウントする場合に使用

//インスタンス生成時にプロパティの値をセット
class Product{
    //クラスプロパティ(生成したインスタンスのカウント用)
    protected static $count = 0;

    // プロパティ
    protected $name;
    protected $price;
    protected $image;

    // コンストラクタ
    //プロパティの値セットはインスタンス生成時の引数で行う
    public function __construct($name, $price, $img){
        $this->name = $name;
        $this->price = $price;
        $this->image = $img;

        // インスタンス生成毎に変数countに1を足す
        self::$count++;
    } 


主な特殊記号

①$this

・メソッド内でのみ使える
・そのメソッドを呼び出しているインスタンス自体を示す

②::

・クラスメソッドやクラスプロパティを呼び出す
・[クラス名]::[プロパティ名];
・[クラス名]::メソッド名{};

③self::

・定義したクラスないでクラスプロパティやクラスメソッドを呼び出す場合に使用
・そのクラス自体を示す

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP】クラスのアクセス権・プロパティ・メソッドなど基本構文のまとめ($this, self::)

【PHP】クラスのアクセス権・プロパティ・メソッドなど基本構文のまとめ

クラスを作成するときの書き方のメモ。

  1. クラス
  2. アクセス権
  3. プロパティ
  4. メソッド
  5. ゲッターとセッター
  6. クラスプロパティとクラスメソッド
  7. インスタンス
  8. コンストラクタ
  9. 主な特殊記号($this, ::, self::, parent::)

クラス

class [クラス名] {}
 └ クラス名は1文字目が大文字

例(クラス名 Product)
class Product{
   //プロパティやメソッド
}

アクセス権

3種類
▼アクセス権が厳しい順

1.private
・定義したクラス内でのみアクセス可。

2.protected
・継承クラス(子クラス)でもアクセス可

3.public
・クラスの外からアクセス可



privateやprotectedなど外からアクセスできなくすることをカプセル化という。

セキュリティ上、プロパティはカプセル化し、値の取得・変更にはメソッドを使う(ゲッターとセッター)。


プロパティ

[アクセス権] [$プロパティ名];

private $name;
protected $size;
public $color;  



▼プロパティの取得

[インスタンス名]->[プロパティ名]
└ プロパティ名に「$」は不要

//メソッドを呼び出しているインスタンスのnameプロパティにアクセス
$this->name;

//インスタンスを格納した変数(例:appleWatch)のnameプロパティにアクセス
$appleWatch->name;



▼プロパティの値変更

[インスタンス名]->[プロパティ名] = [変更後の値]
└ プロパティ名に「$」は不要

//メソッドを呼び出しているインスタンスのnameプロパティにアクセスし値をiphoneに変更
$this->name = 'iphone'

//インスタンスを格納した変数(例:appleWatch)のnameプロパティにアクセスし値をapple_watch_3に変更
$appleWatch->name = 'apple_watch_3'


メソッド

[アクセス権] function [メソッド名](){}
 └ メソッド名の後ろに「()」をつける
 └ メソッド名は大文字・小文字区別あり
 └ $は不要

//hello worldを出力するhelloメソッド
public function hello(){
   echo 'hello world!';
}

//消費税込みの価格を返すメソッド(引数に価格入れる)
public function taxIncludePrice($price){
   return $price*1.01;
}


ゲッターとセッター

特定の役割をするメソッドの名称

▼ゲッター
 └ カプセル化したプロパティの値を取得
 └ メソッド名の冒頭に「get」をつける
 └ 戻り値(return)にする

▼セッター
 └ カプセル化したプロパティの値を変更
 └ メソッド名の冒頭に「set」をつける
 └ 「=」でプロパティの値を変更する
 └ プロパティをコンストラクタでセットする場合は不要

いずれもクラスの外からアクセスするため、アクセス権はpublicとする。

//ゲーターの例
public getName(){
 return $this->name;
}


//セッターの例
public setName(){
 $this->name = '変更する値';
}


クラスプロパティとクラスメソッド

  • 個々のインスタンスではなく、クラスが持つデータにアクセスする場合に定義する。
  • アクセス権の後に「static」
  • アクセスは「クラス名::」
  • 定義したクラス内で呼び出す場合は「self::」

<使用例>
・生成したインスタンスの数をカウントする。
・すべてのインスタンスの中から、指定した条件に一致するインスタンスを抽出する。


クラスプロパティ

▼クラスプロパティの定義
[アクセス権] static $[プロパティ名]

▼クラスプロパティの取得
[クラス名]::$[プロパティ名]
 └ クラス内で設定する場合、クラス名は「self」になる
 └ 「$」必要。(普通のプロパティと異なる)
 └ アロー「->」が「::」に置き換わる

//クラスプロパティの定義
protected static $count=0;

//クラスプロパティの取得
//クラス内
self::$count;

//クラス外(クラス名Productが持つプロパティにアクセス)
Product::$count;


クラスメソッド

▼クラスメソッドの定義
[アクセス権] static function [メソッド名](){}

▼クラスメソッドの呼び出し
[クラス名]::[メソッド名](){}
 └ クラス内で設定する場合、クラス名は「self」になる
 └ 「$」必要。(普通のプロパティと異なる)
 └ アロー「->」が「::」に置き換わる

//クラスメソッドの定義
protected static function getCount(){
 //処理
};

//クラスメソッドの呼び出し
//クラス内
self::getCount();

//クラス外(クラス名Productが持つクラスメソッドの呼び出し)
Product::getCount();


インスタンスの生成

$変数名 = new クラス名()
└ new:インスタンスの生成
└ 生成したインスタンスを変数に格納

$appleWatch = new Product();


コンストラクタ

public function __construct(){}

・インスタンス生成時に自動で呼び出されるメソッド
・プロパティのセットで使用
・生成したインスタンスの数をカウントする場合に使用

//インスタンス生成時にプロパティの値をセット
class Product{
    //クラスプロパティ(生成したインスタンスのカウント用)
    protected static $count = 0;

    // プロパティ
    protected $name;
    protected $price;
    protected $image;

    // コンストラクタ
    //プロパティの値セットはインスタンス生成時の引数で行う
    public function __construct($name, $price, $img){
        $this->name = $name;
        $this->price = $price;
        $this->image = $img;

        // インスタンス生成毎に変数countに1を足す
        self::$count++;
    } 


主な特殊記号

①$this

・メソッド内でのみ使える
・そのメソッドを呼び出しているインスタンス自体を示す

②::

・クラスメソッドやクラスプロパティを呼び出す
・[クラス名]::[プロパティ名];
・[クラス名]::メソッド名{};

③self::

・定義したクラスないでクラスプロパティやクラスメソッドを呼び出す場合に使用
・そのクラス自体を示す

④parent::

・親クラスを示す
・子クラス(継承クラス)内で親クラスのメソッドを呼び出す
・親クラス内で定義されているコンストラクタの呼び出しなど

子クラスのコンストラクタで、親クラスのコンストラクタを呼び出し
public function __construct($name, $price, $img, $size){
  //親クラスで定義したコンストラクタを呼び出し
  parent::__construct($name, $price, $img);

  //新たにプロパティを追加
  $this->size =$size;
}






  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP】クラスのアクセス権・プロパティ・メソッドなど基本構文のまとめ($this, self::, parent::)

【PHP】クラスのアクセス権・プロパティ・メソッドなど基本構文のまとめ

クラスを作成するときの書き方のメモ。

  1. クラス
  2. アクセス権
  3. プロパティ
  4. メソッド
  5. ゲッターとセッター
  6. クラスプロパティとクラスメソッド
  7. インスタンス
  8. コンストラクタ
  9. 主な特殊記号($this, ::, self::, parent::)

クラス

class [クラス名] {}
 └ クラス名は1文字目が大文字

例(クラス名 Product)
class Product{
   //プロパティやメソッド
}

アクセス権

3種類
▼アクセス権が厳しい順

1.private
・定義したクラス内でのみアクセス可。

2.protected
・継承クラス(子クラス)でもアクセス可

3.public
・クラスの外からアクセス可



privateやprotectedなど外からアクセスできなくすることをカプセル化という。

セキュリティ上、プロパティはカプセル化し、値の取得・変更にはメソッドを使う(ゲッターとセッター)。


プロパティ

[アクセス権] [$プロパティ名];

private $name;
protected $size;
public $color;  



▼プロパティの取得

[インスタンス名]->[プロパティ名]
└ プロパティ名に「$」は不要

//メソッドを呼び出しているインスタンスのnameプロパティにアクセス
$this->name;

//インスタンスを格納した変数(例:appleWatch)のnameプロパティにアクセス
$appleWatch->name;



▼プロパティの値変更

[インスタンス名]->[プロパティ名] = [変更後の値]
└ プロパティ名に「$」は不要

//メソッドを呼び出しているインスタンスのnameプロパティにアクセスし値をiphoneに変更
$this->name = 'iphone'

//インスタンスを格納した変数(例:appleWatch)のnameプロパティにアクセスし値をapple_watch_3に変更
$appleWatch->name = 'apple_watch_3'


メソッド

[アクセス権] function [メソッド名](){}
 └ メソッド名の後ろに「()」をつける
 └ メソッド名は大文字・小文字区別あり
 └ $は不要

//hello worldを出力するhelloメソッド
public function hello(){
   echo 'hello world!';
}

//消費税込みの価格を返すメソッド(引数に価格入れる)
public function taxIncludePrice($price){
   return $price*1.01;
}


ゲッターとセッター

特定の役割をするメソッドの名称

▼ゲッター
 └ カプセル化したプロパティの値を取得
 └ メソッド名の冒頭に「get」をつける
 └ 戻り値(return)にする

▼セッター
 └ カプセル化したプロパティの値を変更
 └ メソッド名の冒頭に「set」をつける
 └ 「=」でプロパティの値を変更する
 └ プロパティをコンストラクタでセットする場合は不要

いずれもクラスの外からアクセスするため、アクセス権はpublicとする。

//ゲーターの例
public getName(){
 return $this->name;
}


//セッターの例
public setName(){
 $this->name = '変更する値';
}


クラスプロパティとクラスメソッド

  • 個々のインスタンスではなく、クラスが持つデータにアクセスする場合に定義する。
  • アクセス権の後に「static」
  • アクセスは「クラス名::」
  • 定義したクラス内で呼び出す場合は「self::」

<使用例>
・生成したインスタンスの数をカウントする。
・すべてのインスタンスの中から、指定した条件に一致するインスタンスを抽出する。


クラスプロパティ

▼クラスプロパティの定義
[アクセス権] static $[プロパティ名]

▼クラスプロパティの取得
[クラス名]::$[プロパティ名]
 └ クラス内で設定する場合、クラス名は「self」になる
 └ 「$」必要。(普通のプロパティと異なる)
 └ アロー「->」が「::」に置き換わる

//クラスプロパティの定義
protected static $count=0;

//クラスプロパティの取得
//クラス内
self::$count;

//クラス外(クラス名Productが持つプロパティにアクセス)
Product::$count;


クラスメソッド

▼クラスメソッドの定義
[アクセス権] static function [メソッド名](){}

▼クラスメソッドの呼び出し
[クラス名]::[メソッド名](){}
 └ クラス内で設定する場合、クラス名は「self」になる
 └ 「$」必要。(普通のプロパティと異なる)
 └ アロー「->」が「::」に置き換わる

//クラスメソッドの定義
protected static function getCount(){
 //処理
};

//クラスメソッドの呼び出し
//クラス内
self::getCount();

//クラス外(クラス名Productが持つクラスメソッドの呼び出し)
Product::getCount();


インスタンスの生成

$変数名 = new クラス名()
└ new:インスタンスの生成
└ 生成したインスタンスを変数に格納
└ 変数は大文字、数値も使用可

$appleWatch7 = new Product();


コンストラクタ

public function __construct(){}

・インスタンス生成時に自動で呼び出されるメソッド
・プロパティのセットで使用
・生成したインスタンスの数をカウントする場合に使用

//インスタンス生成時にプロパティの値をセット
class Product{
    //クラスプロパティ(生成したインスタンスのカウント用)
    protected static $count = 0;

    // プロパティ
    protected $name;
    protected $price;
    protected $image;

    // コンストラクタ
    //プロパティの値セットはインスタンス生成時の引数で行う
    public function __construct($name, $price, $img){
        $this->name = $name;
        $this->price = $price;
        $this->image = $img;

        // インスタンス生成毎に変数countに1を足す
        self::$count++;
    } 


主な特殊記号

①$this

・メソッド内でのみ使える
・そのメソッドを呼び出しているインスタンス自体を示す

②::

・クラスメソッドやクラスプロパティを呼び出す
・[クラス名]::[プロパティ名];
・[クラス名]::メソッド名{};

③self::

・定義したクラスないでクラスプロパティやクラスメソッドを呼び出す場合に使用
・そのクラス自体を示す

④parent::

・親クラスを示す
・子クラス(継承クラス)内で親クラスのメソッドを呼び出す
・親クラス内で定義されているコンストラクタの呼び出しなど

▼子クラスのコンストラクタで、親クラスのコンストラクタを呼び出す例

public function __construct($name, $price, $img, $size){
  //親クラスで定義したコンストラクタを呼び出し
  parent::__construct($name, $price, $img);

  //新たにプロパティを追加
  $this->size =$size;
}

⑤return

・名称:戻り値
・戻り値の値をメソッドと置き換える(戻り値を返す)
・returnが実行されると処理が終了する

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPによるEnumの実装方法がついに決着した

ときどきPHPStanの更新を一応眺めているんだけど、PHPStan 0.12.20 でいつの間にか欲しかった機能が実装されていた。
@param に定数が使えるようになっていた。定数だけだと一見無意味だけれど、ワイルドカードやunionが使える。

これによって、今まで様々な実装があったEnumをどうするかという問題が解決した。
単にconstを集めたシンプルなクラスにすれば良い。

<?php
namespace App;
class Env
{
    public const DEVELOP = 'development';
    public const STAGING = 'staging';
    public const PRODUCTION = 'production';
}
<?php
namespace App;
class Main
{
    /**
     * @param Env::* $env
     */
    public static function doSomethingByEnv($env): void
    {
    }

    public static function main(): void
    {
        self::doSomethingByEnv('development');
        self::doSomethingByEnv(Env::DEVELOP);
        self::doSomethingByEnv('dev');
    }
}

PHPStan実行結果

zsh % php7.4 vendor/bin/phpstan analyse src        [~/prog/php/phpstan/sample1]
Note: Using configuration file /home/nishimura/prog/php/phpstan/sample1/phpstan.neon.dist.
 3/3 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%

 ------ ----------------------------------------------------------------- 
  Line   Main.php                                                         
 ------ ----------------------------------------------------------------- 
  16     Parameter #1 $env of static method App\Main::doSomethingByEnv()  
         expects 'development'|'production'|'staging', 'dev' given.       
 ------ ----------------------------------------------------------------- 


 [ERROR] Found 1 error                                                          

enum.png

PHPらしい手抜き加減がなかなか良い感じである。
unionにすれば単純なチェックボックスのフォームみたいな処理でも型チェックができそうだ。
たぶん @param int|float $id とかよりも @param 'GET'|'POST' $method とかの方が使い道がある。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

パターンを網羅してstaticキーワードの挙動を理解する_クラスプロパティ/クラスメソッド編

はじめに

PHP Manualの static キーワードに関するページ(日本語版, 英語版)を読んで、どのようなクラスプロパティ/クラスメソッド定義がOKでどのようなのがNGなのか気になりました。

PHPにはクラスの他にもインターフェースやトレイトというクラスっぽいものもあるので、 どこの中で どう定義するか のパターンを考えて実験してみることにしました。

どこの中で

クラス

PHPには ただのクラス の他にも abstractクラスfinalクラス があります。 abstract かつ final なクラス はありません。

OKなクラス定義
// ただのクラス
class SomeClass {}

// abstractクラス
abstract class SomeAbstractClass {}

// finalクラス
final class SomeFinalClass {}

abstract かつ final なクラス を作ろうとするとどうなるかも実験してみました。

NGなクラス定義
// abstractなfinalクラスを作りたい
abstract final class SomeAbstractFinalClass {}
// => PHP Fatal error:  Cannot use the final modifier on an abstract class

// finalなabstractクラスを作りたい
final abstract class SomeFinalAbstractClass {}
// => PHP Fatal error:  Cannot use the final modifier on an abstract class

脱線します。 abstract かつ final なクラス を作れないことに今までは納得していたのですが、今、納得できなくなりました。

今までは次のように考えて納得していました。

abstractクラス のインスタンスを生成するためには abstractメソッド を全て実装した継承クラスを作らなければならない。一方で finalクラス の継承クラスを作ることはできない。 abstract かつ final なクラス があったとしても、そのクラスのインスタンスを生成することはできないことになるから、言語仕様で abstract かつ final なクラス が許可されていないのは納得できる。

しかし今、次のように考えて納得できなくなりました。

abstract かつ final なクラス はインスタンスを生成して使うことができず、また継承クラスを作って使うこともできない。だが、そのクラスのクラスメソッドを使うことはできる。もし インスタンスを生成して使いたくはないし、継承クラスを作って使いたくもないが、クラスメソッドだけは使いたい ようなクラスを作りたくなったとすると abstract かつ final なクラス が必要になるのではないか。使い道があるのに、理由がなく言語仕様で許可されていないとしたら納得できない。

脱線が長くなりましたが、PHPの仕様や実装上の理由、もしくはPHPの思想、オブジェクト指向プログラミングといった観点から理由がわかるよ、という方がいらっしゃいましたらご教示いただけると喜びます。

インターフェース

インターフェースはただのインターフェースしかありません。

OKなインターフェース定義
// ただのインターフェース
interface SomeInterface {}

abstractなインターフェースfinalなインターフェース はありません。

NGなインターフェース定義
// abstractなインターフェースを作りたい
abstract interface SomeAbstractInterface {}
// => PHP Parse error:  syntax error, unexpected 'interface' (T_INTERFACE), expecting abstract (T_ABSTRACT) or final (T_FINAL) or class (T_CLASS)

// finalなインターフェースを作りたい
final interface SomeFinalInterface {}
// => PHP Parse error:  syntax error, unexpected 'interface' (T_INTERFACE), expecting abstract (T_ABSTRACT) or final (T_FINAL) or class (T_CLASS)

// abstractでfinalなインターフェースを作りたい
abstract final interface SomeAbstractFinalInterface {}
// => PHP Fatal error:  Cannot use the final modifier on an abstract class

// finalでabstractなインターフェースを作りたい
final abstract interface SomeFinalAbstractInterface {}
// => PHP Fatal error:  Cannot use the final modifier on an abstract class

インターフェースは何もしなくても abstract のようなものなので、abstractなインターフェース が許可されていないのは納得できます。一方、インターフェースを extend してほしくない場合に finalなインターフェース のような需要があるのではないかと思いました。

トレイト

トレイトもただのトレイトしかありません

OKなトレイト定義
// ただのトレイト
trait SomeTrait {}

abstractなトレイトfinalなトレイト はありません。

NGなトレイト定義
// abstractなトレイトを作りたい
abstract trait SomeAbstractTrait {}
// => PHP Parse error:  syntax error, unexpected 'trait' (T_TRAIT), expecting abstract (T_ABSTRACT) or final (T_FINAL) or class (T_CLASS)

// finalなトレイトを作りたい
final trait SomeFinalTrait {}
// => PHP Parse error:  syntax error, unexpected 'trait' (T_TRAIT), expecting abstract (T_ABSTRACT) or final (T_FINAL) or class (T_CLASS)

// abstractでfinalなトレイトを作りたい
abstract final trait SomeAbstractFinalTrait {}
// => PHP Fatal error:  Cannot use the final modifier on an abstract class

// finalでabstractトレイトを作りたい
final abstract trait SomeFinalAbstractTrait {}
// => PHP Fatal error:  Cannot use the final modifier on an abstract class

トレイトは実装を定義するためのものだと思っているので、 abstractなトレイト が許可されていないのは納得できます。一方、他のクラスやトレイトで use したときに、 use されたトレイトの実装を上書いてほしくない場合に finalなトレイト のような需要があるのではないかと思いました。

どう定義するか

クラスプロパティ

アクセス権を3パターン試します。アクセス権を宣言しないパターンと var を使うパターンは現在は使うべきではないと考えているので試しません。

また、クラスプロパティの宣言時に初期化するかどうかで2パターン試します。

アクセス権で3パターン x 初期化するかで2パターン = 6パターン の宣言方法を試すことになりました。

クラスプロパティの宣言パターン
public static $public_static_property_without_initialization;
public static $public_static_property_with_initialization = null;

protected static $protected_static_property_without_initialization;
protected static $protected_static_property_with_initialization = null;

private static $private_static_property_without_initialization;
private static $private_static_property_with_initialization = null;

クラスメソッド

アクセス権を3パターン試します。アクセス権を宣言しないパターンは現在は使うべきではないと考えているので試しません。

また、本体があるかどうかで2パターン試します。

さらに、 abstract キーワードと final キーワードのくっつき方の組み合わせで5パターン試します。

アクセス権で3パターン x 本体があるかどうかで2パターン x 5パターン = 30パターン の宣言方法を試すことになりました。

クラスメソッドの宣言パターン
// public x 10パターン
public static function public_static_method_without_body();
public static function public_static_method_with_body() {}

abstract public static function abstract_public_static_method_without_body();
abstract public static function abstract_public_static_method_with_body() {}

final public static function final_public_static_method_without_body();
final public static function final_public_static_method_with_body() {}

abstract final public static function abstract_final_public_static_method_without_body();
abstract final public static function abstract_final_public_static_method_with_body() {}

final abstract public static function final_abstract_public_static_method_without_body();
final abstract public static function final_abstract_public_static_method_with_body() {}

// protected x 10パターン
protected static function protected_static_method_without_body();
protected static function protected_static_method_with_body() {}

abstract protected static function abstract_protected_static_method_without_body();
abstract protected static function abstract_protected_static_method_with_body() {}

final protected static function final_protected_static_method_without_body();
final protected static function final_protected_static_method_with_body() {}

abstract final protected static function abstract_final_protected_static_method_without_body();
abstract final protected static function abstract_final_protected_static_method_with_body() {}

final abstract protected static function final_abstract_protected_static_method_without_body();
final abstract protected static function final_abstract_protected_static_method_with_body() {}

// private x 10パターン
private static function private_static_method_without_body();
private static function private_static_method_with_body() {}

abstract private static function abstract_private_static_method_without_body();
abstract private static function abstract_private_static_method_with_body() {}

final private static function final_private_static_method_without_body();
final private static function final_private_static_method_with_body() {}

abstract final private static function abstract_final_private_static_method_without_body();
abstract final private static function abstract_final_private_static_method_with_body() {}

final abstract private static function final_abstract_private_static_method_without_body();
final abstract private static function final_abstract_private_static_method_with_body() {}

実験

エラーになるものをコメントアウトして示します。

ただのクラス

ただのクラス
class SomeClass
{
    public static $public_static_property_without_initialization;
    public static $public_static_property_with_initialization = null;

    protected static $protected_static_property_without_initialization;
    protected static $protected_static_property_with_initialization = null;

    private static $private_static_property_without_initialization;
    private static $private_static_property_with_initialization = null;

    // public x 10パターン
    // public static function public_static_method_without_body();
    public static function public_static_method_with_body() {}

    // abstract public static function abstract_public_static_method_without_body();
    // abstract public static function abstract_public_static_method_with_body() {}

    // final public static function final_public_static_method_without_body();
    final public static function final_public_static_method_with_body() {}

    // abstract final public static function abstract_final_public_static_method_without_body();
    // abstract final public static function abstract_final_public_static_method_with_body() {}

    // final abstract public static function final_abstract_public_static_method_without_body();
    // final abstract public static function final_abstract_public_static_method_with_body() {}

    // protected x 10パターン
    // protected static function protected_static_method_without_body();
    protected static function protected_static_method_with_body() {}

    // abstract protected static function abstract_protected_static_method_without_body();
    // abstract protected static function abstract_protected_static_method_with_body() {}

    // final protected static function final_protected_static_method_without_body();
    final protected static function final_protected_static_method_with_body() {}

    // abstract final protected static function abstract_final_protected_static_method_without_body();
    // abstract final protected static function abstract_final_protected_static_method_with_body() {}

    // final abstract protected static function final_abstract_protected_static_method_without_body();
    // final abstract protected static function final_abstract_protected_static_method_with_body() {}

    // private x 10パターン
    // private static function private_static_method_without_body();
    private static function private_static_method_with_body() {}

    // abstract private static function abstract_private_static_method_without_body();
    // abstract private static function abstract_private_static_method_with_body() {}

    // final private static function final_private_static_method_without_body();
    final private static function final_private_static_method_with_body() {}

    // abstract final private static function abstract_final_private_static_method_without_body();
    // abstract final private static function abstract_final_private_static_method_with_body() {}

    // final abstract private static function final_abstract_private_static_method_without_body();
    // final abstract private static function final_abstract_private_static_method_with_body() {}
}

コメントを消したものを再掲します。

ただのクラス
class SomeClass
{
    public static $public_static_property_without_initialization;
    public static $public_static_property_with_initialization = null;

    protected static $protected_static_property_without_initialization;
    protected static $protected_static_property_with_initialization = null;

    private static $private_static_property_without_initialization;
    private static $private_static_property_with_initialization = null;

    public static function public_static_method_with_body() {}
    final public static function final_public_static_method_with_body() {}

    protected static function protected_static_method_with_body() {}
    final protected static function final_protected_static_method_with_body() {}

    private static function private_static_method_with_body() {}
    final private static function final_private_static_method_with_body() {}
}

見慣れた光景になりましたね。

abstractクラス

abstractクラス
abstract class SomeAbstractClass
{
    public static $public_static_property_without_initialization;
    public static $public_static_property_with_initialization = null;

    protected static $protected_static_property_without_initialization;
    protected static $protected_static_property_with_initialization = null;

    private static $private_static_property_without_initialization;
    private static $private_static_property_with_initialization = null;

    // public x 10パターン
    // public static function public_static_method_without_body();
    public static function public_static_method_with_body() {}

    abstract public static function abstract_public_static_method_without_body();
    // abstract public static function abstract_public_static_method_with_body() {}

    // final public static function final_public_static_method_without_body();
    final public static function final_public_static_method_with_body() {}

    // abstract final public static function abstract_final_public_static_method_without_body();
    // abstract final public static function abstract_final_public_static_method_with_body() {}

    // final abstract public static function final_abstract_public_static_method_without_body();
    // final abstract public static function final_abstract_public_static_method_with_body() {}

    // protected x 10パターン
    // protected static function protected_static_method_without_body();
    protected static function protected_static_method_with_body() {}

    abstract protected static function abstract_protected_static_method_without_body();
    // abstract protected static function abstract_protected_static_method_with_body() {}

    // final protected static function final_protected_static_method_without_body();
    final protected static function final_protected_static_method_with_body() {}

    // abstract final protected static function abstract_final_protected_static_method_without_body();
    // abstract final protected static function abstract_final_protected_static_method_with_body() {}

    // final abstract protected static function final_abstract_protected_static_method_without_body();
    // final abstract protected static function final_abstract_protected_static_method_with_body() {}

    // private x 10パターン
    // private static function private_static_method_without_body();
    private static function private_static_method_with_body() {}

    // abstract private static function abstract_private_static_method_without_body();
    // abstract private static function abstract_private_static_method_with_body() {}

    // final private static function final_private_static_method_without_body();
    final private static function final_private_static_method_with_body() {}

    // abstract final private static function abstract_final_private_static_method_without_body();
    // abstract final private static function abstract_final_private_static_method_with_body() {}

    // final abstract private static function final_abstract_private_static_method_without_body();
    // final abstract private static function final_abstract_private_static_method_with_body() {}
}

コメントを消したものを再掲します。

abstractクラス
abstract class SomeAbstractClass
{
    public static $public_static_property_without_initialization;
    public static $public_static_property_with_initialization = null;

    protected static $protected_static_property_without_initialization;
    protected static $protected_static_property_with_initialization = null;

    private static $private_static_property_without_initialization;
    private static $private_static_property_with_initialization = null;

    public static function public_static_method_with_body() {}    
    abstract public static function abstract_public_static_method_without_body();
    final public static function final_public_static_method_with_body() {}

    protected static function protected_static_method_with_body() {}    
    abstract protected static function abstract_protected_static_method_without_body();
    final protected static function final_protected_static_method_with_body() {}

    private static function private_static_method_with_body() {}
    final private static function final_private_static_method_with_body() {}
}

クラスがabstractになったので abstract public static functionabstract protected static function が許可されるようになりました。 abstract private static function は意味わかんないので相変わらず許可されません。

finalクラス

finalクラス
final class SomeFinalClass
{
    public static $public_static_property_without_initialization;
    public static $public_static_property_with_initialization = null;

    protected static $protected_static_property_without_initialization;
    protected static $protected_static_property_with_initialization = null;

    private static $private_static_property_without_initialization;
    private static $private_static_property_with_initialization = null;

    // public x 10パターン
    // public static function public_static_method_without_body();
    public static function public_static_method_with_body() {}

    // abstract public static function abstract_public_static_method_without_body();
    // abstract public static function abstract_public_static_method_with_body() {}

    // final public static function final_public_static_method_without_body();
    final public static function final_public_static_method_with_body() {}

    // abstract final public static function abstract_final_public_static_method_without_body();
    // abstract final public static function abstract_final_public_static_method_with_body() {}

    // final abstract public static function final_abstract_public_static_method_without_body();
    // final abstract public static function final_abstract_public_static_method_with_body() {}

    // protected x 10パターン
    // protected static function protected_static_method_without_body();
    protected static function protected_static_method_with_body() {}

    // abstract protected static function abstract_protected_static_method_without_body();
    // abstract protected static function abstract_protected_static_method_with_body() {}

    // final protected static function final_protected_static_method_without_body();
    final protected static function final_protected_static_method_with_body() {}

    // abstract final protected static function abstract_final_protected_static_method_without_body();
    // abstract final protected static function abstract_final_protected_static_method_with_body() {}

    // final abstract protected static function final_abstract_protected_static_method_without_body();
    // final abstract protected static function final_abstract_protected_static_method_with_body() {}

    // private x 10パターン
    // private static function private_static_method_without_body();
    private static function private_static_method_with_body() {}

    // abstract private static function abstract_private_static_method_without_body();
    // abstract private static function abstract_private_static_method_with_body() {}

    // final private static function final_private_static_method_without_body();
    final private static function final_private_static_method_with_body() {}

    // abstract final private static function abstract_final_private_static_method_without_body();
    // abstract final private static function abstract_final_private_static_method_with_body() {}

    // final abstract private static function final_abstract_private_static_method_without_body();
    // final abstract private static function final_abstract_private_static_method_with_body() {}
}

コメントを消したものを再掲します。

finalクラス
final class SomeFinalClass
{
    public static $public_static_property_without_initialization;
    public static $public_static_property_with_initialization = null;

    protected static $protected_static_property_without_initialization;
    protected static $protected_static_property_with_initialization = null;

    private static $private_static_property_without_initialization;
    private static $private_static_property_with_initialization = null;

    public static function public_static_method_with_body() {}
    final public static function final_public_static_method_with_body() {}

    protected static function protected_static_method_with_body() {}
    final protected static function final_protected_static_method_with_body() {}

    private static function private_static_method_with_body() {}
    final private static function final_private_static_method_with_body() {}
}

ただのクラスの場合と同じですね。

ただのインターフェース

ただのインターフェース
interface SomeInterface
{
    // public static $public_static_property_without_initialization;
    // public static $public_static_property_with_initialization = null;

    // protected static $protected_static_property_without_initialization;
    // protected static $protected_static_property_with_initialization = null;

    // private static $private_static_property_without_initialization;
    // private static $private_static_property_with_initialization = null;

    // public x 10パターン
    public static function public_static_method_without_body();
    // public static function public_static_method_with_body() {}

    // abstract public static function abstract_public_static_method_without_body();
    // abstract public static function abstract_public_static_method_with_body() {}

    // final public static function final_public_static_method_without_body();
    // final public static function final_public_static_method_with_body() {}

    // abstract final public static function abstract_final_public_static_method_without_body();
    // abstract final public static function abstract_final_public_static_method_with_body() {}

    // final abstract public static function final_abstract_public_static_method_without_body();
    // final abstract public static function final_abstract_public_static_method_with_body() {}

    // protected x 10パターン
    // protected static function protected_static_method_without_body();
    // protected static function protected_static_method_with_body() {}

    // abstract protected static function abstract_protected_static_method_without_body();
    // abstract protected static function abstract_protected_static_method_with_body() {}

    // final protected static function final_protected_static_method_without_body();
    // final protected static function final_protected_static_method_with_body() {}

    // abstract final protected static function abstract_final_protected_static_method_without_body();
    // abstract final protected static function abstract_final_protected_static_method_with_body() {}

    // final abstract protected static function final_abstract_protected_static_method_without_body();
    // final abstract protected static function final_abstract_protected_static_method_with_body() {}

    // private x 10パターン
    // private static function private_static_method_without_body();
    // private static function private_static_method_with_body() {}

    // abstract private static function abstract_private_static_method_without_body();
    // abstract private static function abstract_private_static_method_with_body() {}

    // final private static function final_private_static_method_without_body();
    // final private static function final_private_static_method_with_body() {}

    // abstract final private static function abstract_final_private_static_method_without_body();
    // abstract final private static function abstract_final_private_static_method_with_body() {}

    // final abstract private static function final_abstract_private_static_method_without_body();
    // final abstract private static function final_abstract_private_static_method_with_body() {}
}

コメントを消したものを再掲します。

ただのインターフェース
interface SomeInterface
{
    public static function public_static_method_without_body();
}

1つしか残りませんでした。

ただのトレイト

ただのトレイト
trait SomeTrait
{
    public static $public_static_property_without_initialization;
    public static $public_static_property_with_initialization = null;

    protected static $protected_static_property_without_initialization;
    protected static $protected_static_property_with_initialization = null;

    private static $private_static_property_without_initialization;
    private static $private_static_property_with_initialization = null;

    // public x 10パターン
    // public static function public_static_method_without_body();
    public static function public_static_method_with_body() {}

    abstract public static function abstract_public_static_method_without_body();
    // abstract public static function abstract_public_static_method_with_body() {}

    // final public static function final_public_static_method_without_body();
    final public static function final_public_static_method_with_body() {}

    // abstract final public static function abstract_final_public_static_method_without_body();
    // abstract final public static function abstract_final_public_static_method_with_body() {}

    // final abstract public static function final_abstract_public_static_method_without_body();
    // final abstract public static function final_abstract_public_static_method_with_body() {}

    // protected x 10パターン
    // protected static function protected_static_method_without_body();
    protected static function protected_static_method_with_body() {}

    abstract protected static function abstract_protected_static_method_without_body();
    // abstract protected static function abstract_protected_static_method_with_body() {}

    // final protected static function final_protected_static_method_without_body();
    final protected static function final_protected_static_method_with_body() {}

    // abstract final protected static function abstract_final_protected_static_method_without_body();
    // abstract final protected static function abstract_final_protected_static_method_with_body() {}

    // final abstract protected static function final_abstract_protected_static_method_without_body();
    // final abstract protected static function final_abstract_protected_static_method_with_body() {}

    // private x 10パターン
    // private static function private_static_method_without_body();
    private static function private_static_method_with_body() {}

    // abstract private static function abstract_private_static_method_without_body();
    // abstract private static function abstract_private_static_method_with_body() {}

    // final private static function final_private_static_method_without_body();
    final private static function final_private_static_method_with_body() {}

    // abstract final private static function abstract_final_private_static_method_without_body();
    // abstract final private static function abstract_final_private_static_method_with_body() {}

    // final abstract private static function final_abstract_private_static_method_without_body();
    // final abstract private static function final_abstract_private_static_method_with_body() {}
}

コメントを消したものを再掲します。

ただのトレイト
trait SomeTrait
{
    public static $public_static_property_without_initialization;
    public static $public_static_property_with_initialization = null;

    protected static $protected_static_property_without_initialization;
    protected static $protected_static_property_with_initialization = null;

    private static $private_static_property_without_initialization;
    private static $private_static_property_with_initialization = null;

    public static function public_static_method_with_body() {}
    abstract public static function abstract_public_static_method_without_body();
    final public static function final_public_static_method_with_body() {}

    protected static function protected_static_method_with_body() {}    
    abstract protected static function abstract_protected_static_method_without_body();
    final protected static function final_protected_static_method_with_body() {}

    private static function private_static_method_with_body() {}
    final private static function final_private_static_method_with_body() {}
}

abstractクラスと同じになるんですか!?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pythonで画像を送信、phpで保存する

色々わr・・・面白いことに使えそうだからメモしとく

pic_post.py
import requests
#こちら送信側→ローカルに置く
with open("img.jpg", "rb") as f:#画像をopen(読み込みみたいな?)する
    url='http://hogehoge.jp/pic_save.php'#送り先
    r = requests.post(url, f.read())#送信
pic_save.php
<?php
//こちら受信側→サーバ側に置いておく
    $bin = file_get_contents("php://input");//受信したモノを取り出し
    file_put_contents('./img.jpg',$bin);//同じディレクトリに『img.jpg』というファイル名で保存する
?>

とりあえずは上のコードで動くはず
f.read()の意味は何だよとかは追記するかも
拡張子が違う場合(png、gif)やら画像を選びたい場合やらとかも本当は考えたいところ

参考

[PHP]画像をダウンロードしてサーバーの特定のディレクトリに保存する
http://codaholic.org/?p=341

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelでログ出力を行う

前提条件

eclipseでLaravel開発環境を構築する。デバッグでブレークポイントをつけて止める。(WindowsもVagrantもdockerも)
本記事は上記が完了している前提で書かれています
プロジェクトの作成もapacheの設定も上記で行っています

Controllerにメソッド追加

(1) /sample/app/Http/Controllers/SampleController.phpに下記を追記
use Illuminate\Support\Facades\Log;

(2) /sample/app/Http/Controllers/SampleController.phpにlogメソッドを追記

    public function log(Request $request)
    {
        Log::emergency('ログサンプル', ['memo' => 'sample1']);
        Log::alert('ログサンプル', ['memo' => 'sample1']);
        Log::critical('ログサンプル', ['memo' => 'sample1']);
        Log::error('ログサンプル', ['memo' => 'sample1']);
        Log::warning('ログサンプル', ['memo' => 'sample1']);
        Log::notice('ログサンプル', ['memo' => 'sample1']);
        Log::info('ログサンプル', ['memo' => 'sample1']);
        Log::debug('ログサンプル', ['memo' => 'sample1']);

        return view('sample.log');
    }

Logクラスのログ出力メソッド名はログレベルに相当します
emergencyは最も重要度が高く、debugは最も重要度が低いです

(2) /sample/routes/web.phpに下記を追記
Route::get('sample/log', 'SampleController@log');

viewの作成

/sample/resources/views/sample/log.blade.phpファイル作成

log.blade.php
<html>
    <head>
        <title>sample</title>
    </head>
    <body>
        <div>log</div>
    </body>
</html>

logの設定

(1) /sample/config/logging.phpファイル修正
logging.phpは配列を返すファイルになっています
default要素の値が使用するログチャンネルとなります
ログ出力の際には、どこ(ファイル、DB、メール等)に何(ファイル名、行番号、リクエストURL等)を、どのように(日時の形式等)出力するかを決めなければなりません
どこ、何、どのようにの組み合わせを定義したものをログチャンネルと呼ぶと考えて差し支えないと思います
default要素はenv('LOG_CHANNEL', 'stack')となっていると思います。つまりstackチャンネルを使用します

stackチャンネルはどのような定義になっているか見ていきます

logging.phpファイルのchannels要素に様々なログチャンネルが定義されています
'channels'=>'stack'要素がstackチャンネルです
'channels'=>'stack'要素(stackチャンネル)を修正します

    'channels' => [
        'stack' => [
            'driver' => 'stack',
            'ignore_exceptions' => false,
            'channels' => ['single', 'daily'],
            'name' => 'stack-channel',
        ],
     ‥‥

channels要素を修正し、name要素を追加しました
stackチャンネルというのは複数のログチャンネルを1つにまとめたものです。したがって、使用するログチャンネルを'channels'=>'stack'=>'channels'要素に書くだけです
今回はsingleチャンネルとdailyチャンネルを使用する設定にしました
name要素はチャンネル名です。お好きな名前を設定してください

では、'channels'=>'single'要素(singleチャンネル)を修正します

    'channels' => [
     ‥‥
        'single' => [
            'driver' => 'single',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
            'tap' => [App\Logging\SampleTap::class],
        ],
     ‥‥

singleチャンネルは1つのファイルにログを出力するチャンネルです。
level要素はどのログレベル以上をログファイルに出力するかを設定しています。例えば、infoと設定した場合、infoより重要度の低いdebugはメソッドが呼ばれたとしてもログに出力されません
path要素でstorage/logs/laravel.logにログを出力する設定になっています。これでどこにログを出力するかは決まりました
次に、何を、どのように出力するかを決めます。それがtap要素です。tap要素にはSampleTapクラスを設定しました
これからSampleTapクラスを作成します

(2) Tapクラスの修正
/sample/app/Loggingフォルダ作成
/sample/app/Logging/SampleTap.phpファイル作成

SampleTap.php
<?php

namespace App\Logging;

use Monolog\Logger;
use Monolog\Formatter\LineFormatter;
use Monolog\Processor\HostnameProcessor;
use Monolog\Processor\WebProcessor;
use Monolog\Processor\IntrospectionProcessor;
use App\Logging\SampleProcessor;

class SampleTap
{
    const FORMAT = "[%datetime%] %level_name% %channel% %message% %extra.file% %extra.line% %extra.class% %extra.function% %extra.hostname% %extra.url% %extra.ip% %extra.http_method% %extra.server% %extra.referrer% %extra.custom% %context.memo%\n";

    public function __invoke($logger)
    {
        $hostnameProcessor = new HostnameProcessor();
        $webProcessor = new WebProcessor();
        $introspectionProcessor = new IntrospectionProcessor(Logger::DEBUG, ['Illuminate\\']);
        $sampleProcessor = new SampleProcessor();

        $lineFormatter = new LineFormatter(static::FORMAT);

        foreach ($logger->getHandlers() as $handler) {
            $handler->pushProcessor($webProcessor);
            $handler->pushProcessor($hostnameProcessor);
            $handler->pushProcessor($introspectionProcessor);
            $handler->pushProcessor($sampleProcessor);
            $handler->setFormatter($lineFormatter);
        }
    }
}

pushProcessorに渡しているのが何を出力するか
setFormatterに渡しているのがどのようにを出力するか
を定義しているクラスです

まずはProcessorを見ていきましょう
Laravelのログ出力はMonologを使用しています
したがってMonologのクラスを使用していきます
HostnameProcessor、WebProcessor、IntrospectionProcessorはMonologが提供してくれているクラスです
他にもProcessorクラスを提供してくれています。
Monologが提供しているProcessor
HostnameProcessorはホスト名を出力してくれます
WebProcessorはリクエストURI、リクエストメソッド、クライアントIP、サーバ名、リファラを出力してくれます
IntrospectionProcessorはファイル、行番号、クラス、関数名を出力してくれます
Monologが提供しているProcessorでは出力されない値をログに出力したい場合、自分でProcessorクラスを作成することになります
SampleProcessorクラスは今回自作したProcessorです。後述します

つぎにFormatterを見ていきましょう
LineFormatterはMonologが提供してくれているクラスです
他にもFormatterクラスを提供してくれています。
Monologが提供しているFormatter
LineFormatterはコンストラクタの第一引数に与えられた文字列に従ってフォーマットしてくれます
今回はSampleTapクラスのFORMAT定数を与えています
LineFormatterは%で囲われた文字列を下記の通りに置換します
%datetime%:ログ出力の日時
%level_name%:ログレベル。Log::error関数でログ出力した場合はerrorがログレベルです
%channel%:logging.phpファイルの'channels'=>'stack'=>'name'
%message%:ログ出力関数の第一引数。Log::error('ログサンプル', ['memo' => 'sample1']);とログ出力した場合、'ログサンプル'
%context.xxx%:ログ出力関数の第二引数。Log::error('ログサンプル', ['memo' => 'sample1']);とログ出力した場合、%context.memo%が'sample1'に置換される
%extra.xxx%:Processorクラスで出力する値。あとでSampleProcessorを作るときに説明します

Formatterを自作することもできますが、ほとんどの場合、Monologが提供しているFormatterで十分でしょう
もし、Formatterを自作する場合は、Monolog\Formatter\FormatterInterfaceをimplementsしたクラスを作ってください

(3) Processorクラスの修正
自作のProcessorクラスをつくります
/sample/app/Logging/SampleProcessor.phpファイル作成

SampleProcessor.php
namespace App\Logging;

use Monolog\Processor\ProcessorInterface;

class SampleProcessor implements ProcessorInterface
{
    public function __invoke(array $record)
    {
        $record['extra']['custom'] = 'sample_extra';
        return $record;
    }
}

$record['extra']['custom']に値を入れて返すと
フォーマット文字列内の%extra.custom%部分が$record['extra']['custom']の値に置換されます
第一要素を'extra'とするのはProcessorを使う上での決まりです
先ほど使用したMonologが提供しているProcessorが置換するのは下記です
HostnameProcessor:extra.hostname
WebProcessor:extra.url、extra.ip、extra.http_method、extra.server、extra.referrer
IntrospectionProcessor:extra.file、extra.line、extra.class、extra.function

(4) 再び/sample/config/logging.phpファイル修正
今度は、'channels'=>'daily'要素(dailyチャンネル)を修正します

    'channels' => [
     ‥‥
        'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
            'days' => 0,
            'tap' => [App\Logging\SampleTap::class],
        ],
     ‥‥

dailyチャンネルは日付毎に1つのファイルにログを出力するチャンネルです。
どこに出力するか:path要素でstorage_path('logs/laravel.log')となっている場合、laravel-YYYY-MM-DD.logというファイル名形式のファイルが日付ごとにできます
何を、どのように出力するか:先ほどsingleチャンネルに設定したのと同じSampleTapクラスを設定しました
days要素は最大何日分のログファイルを保存しておくかです。0の場合、制限無しです

動作確認

http://localhost/laravelSample/sample/log

storage/logs配下を見るとログファイルができており、ログが出力されています

他のログチャンネル

Laravelには他にもログチャンネルが用意されています
下記リンク先の利用可能なチャンネルドライバという箇所に使用できるログチャンネル一覧があります
Laravel ログ
また、config/logging.php内のchannels配列を見ても使えるログチャンネルを確認できます
これらのログチャンネルを使うためのlogging.phpでの設定は
vendor/laravel/framework/src/Illuminate/Log/LogManager.phpのcreateチャンネル名Driverという名前のメソッド(createSlackDriverとかcreateSyslogDriverとか)を見るとわかります。
それらのメソッドは$configを引数に取り、MonologのHandlerクラスのコンストラクタに$configの要素を渡しています
MonologのHandlerクラスのコンストラクタに渡している$configの要素をlogging.phpで定義すれば使うことができます
MonologのHandlerは下記で確認できます
MonologのHandler

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel 既存テーブルにカラムを追加する時のマイグレーションファイルの作成方法

目的

  • 実施方法を毎回検索しているので簡単にまとめる

実施環境

  • ハードウェア環境
項目 情報
OS macOS Catalina(10.15.3)
ハードウェア MacBook Pro (16-inch ,2019)
プロセッサ 2.6 GHz 6コアIntel Core i7
メモリ 16 GB 2667 MHz DDR4
グラフィックス AMD Radeon Pro 5300M 4 GB Intel UHD Graphics 630 1536 MB
  • ソフトウェア環境
項目 情報 備考
PHP バージョン 7.4.3 Homwbrewを用いて導入
Laravel バージョン 7.0.8 commposerを用いて導入
MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いて導入

実施例

  • 下記にカラム追加に必要なマイグレーションファイルの作成コマンドを記載する。

    $ php artisan make:migration add_カラム名_column_to_テーブル名_table --table=テーブル名
    

具体例

  • 「users」テーブルに「flag」カラムを追加したい時のマイグレーションファイルの作成コマンドを下記に記載する。

    $ php artisan make:migration add_flag_column_to_users_table --table=users
    
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

怠惰な大学生が楽単サイト作ったら2万アクセスきた

初投稿です。

はじめに

大学生が求めがちな楽単。サークルや部活に所属しているとその情報は手に入れやすいですが、そういったところに所属していない人にはあまりその情報は回ってこないものです。さらに今年の新入生には例のあのウイルスの影響で授業の情報が入ってきません。この状況では学生によって不利が生まれると思ったので授業のクチコミサイトを作りました。
実際はプログラミング初心者が最初に作りがちな典型的な掲示板です。しかし、思いの外需要があり、 いや、本当は需要あるとわかってた。 2万アクセスを得ました。
これを観ている方の中で大学生の方がおりましたらコピペして作ってみてはいかがでしょうか。

リンク

https://ishiike.matrix.jp

開発環境

macOS Catalina (10.15.4)
Visual Studio Code (1.35.1)
PHP (7.3.16)

サイトの構成

ishiike.png
※その他のページは夏期集中講義など

各曜日のPHPのコード

index.htmlは割愛

<?php
//書き込まれたテキストの関数と何も書き込まれなかった場合のエラーメッセージの関数を最初に定義
$error_message1 = "";
$error_message2 = "";
$error_message3 = "";
$error_message4 = "";
$posted_message ="";
$class_name = ( isset( $_POST["class_name"] ) === true ) ?$_POST["class_name"]: "";
$timetable = ( isset( $_POST["timetable"] ) == true ) ?$_POST["timetable"]: "";
$teacher_name = ( isset( $_POST["teacher_name"] ) == true ) ?$_POST["teacher_name"]: "";
$comment  = ( isset( $_POST["comment"] )  === true ) ?  trim($_POST["comment"])  : "";

//改行を削除
//テキストデータを1行ずつ取得して表示するため改行不可(改善したい)
$comment = str_replace(array("\r\n", "\r", "\n"), '', $comment);

//すべての項目に書き込まれたか判定
//足りている場合テキストファイルに保存
//足りない場合エラーメッセージを代入
if (  isset($_POST["send"] ) ===  true ) {
    if ( $class_name   === "" ) $error_message1 = "授業の名前を入力してください"; 

    if ( $timetable === "" ) $error_message2 = "何時間目か入力してください";

    if ( $teacher_name === "" ) $error_message3 = "先生の名前を入力してください";

    if ( $comment  === "" )  $error_message4 = "コメントを入力してください";

    if( $error_message1 === "" && $error_message2 === "" && $error_message3 === "" && $error_message4 === "" ){
        $fp = fopen( "[曜日名].txt" ,"a" );
        fwrite( $fp ,  $class_name."\t".$timetable."\t".$teacher_name."\t".$comment."\n");
        $posted_message = "書き込みに成功しました。";
    }

}

//テキストファイルの読み込み
$fp = fopen("[曜日名].txt","r");

//テキストデータを1行ずつ取得し空白で分けて配列に
$dataArr = array();
while( $res = fgets( $fp)){
    $tmp = explode("\t",$res);
    $arr = array(
        "class_name"=>$tmp[0],
        "timetable"=>$tmp[1],
        "teacher_name"=>$tmp[2],
        "comment"=>$tmp[3]
    );
    $dataArr[]= $arr;
} 

?>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
    <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8" />
        <title>石池|Ishiike [曜日名]</title>
        <link rel="icon" href="ishiike_logo.png" type="image/png">
    </head>
    <body>
        <header>
        <h1><a href="https://ishiike.matrix.jp"><img src="ishiike_logo.png" width="210px" height="100px"></a>【曜日名】</h1>
        </header>
        <?php echo $posted_message; ?>
        <form method="post" action="">
        授業名:<input type="text" name="class_name" value="<?php echo $class_name; ?>" style="font-size:1em;">
            <?php echo $error_message1; ?><br>
        時間:<input type="text" name="timetable" value="<?php echo $timetable; ?>" style="font-size:1em;">
            <?php echo $error_message2; ?><br>
        先生の名前:<input type="text" name="teacher_name" value="<?php echo $teacher_name; ?>" style="font-size:1em;">
            <?php echo $error_message3; ?><br>
        コメント:<textarea  name="comment" rows="4" cols="80" style="font-size:1em;"><?php echo $comment; ?></textarea>
            <?php echo $error_message4; ?><br>
<br>
          <input type="submit" name="send" value="投稿" rows="2" cols="4" style="font-size:2em;">
        </form>
        <dl>
         <!-- 配列をそれぞれ表示 -->
         <?php foreach( $dataArr as $data ):?>
         <p><span style="font-size:20px;"><?php echo htmlspecialchars($data["class_name"]); ?> : <?php echo htmlspecialchars($data["timetable"]); ?> : <?php echo htmlspecialchars($data["teacher_name"]); ?><br>
         <?php echo htmlspecialchars($data["comment"]); ?></span></p>
        <?php endforeach;?>
</dl>
<br>
        <a href="https://ishiike.matrix.jp/">ホーム</a>
    </body>
</html>

※サークルのページは[サークル名]と[コメント]の2項目

最後に

開設当初は授業だけでしたがサークルのページを追加したらもっとアクセスが増えました。
実はこれを作ろうとしたときPHPにはそれまで触れたことはなく学びながら探り探りで作ったものです。
セキュリティ的にもたくさんの不安を抱えてるものとなっていると思います。
そういった点はご指摘いただけると幸いです。

追記

github
https://github.com/basyakue/Ishiike

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む