20190512のPHPに関する記事は8件です。

PHPのfinally

以下のときのfinally句の挙動

function test($argument)
{
    try
    {
        echo "try\n";
        return $argument;
    }
    finally
    {
        $argument++;
        unset($argument);
        echo "finally\n";
    }
}

$counter = 2;
$result = test($counter);
var_dump($result);
7.1.25-7.3.5
try
finally
int(2)
5.5.0-
try
finally

Notice: Undefined variable: argument in /in/0oTE9 on line 8
NULL

https://3v4l.org/0oTE9


メモ

try句のreturn文でファイルを使用してfinally句でファイルをunlinkするとfile busyになりました。

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

php-master-changes 2019-05-11

今日は typo の修正、不要コードの削除、config.guess、config.sub の更新、テストで使われていた *.jpeg の *.jpg へのリネーム、テストの並列実行対策、不要なドキュメントの削除、テストのコメント内に maintainer zts とあったのを単に zts とする修正があった!

2019-05-11

cmb69: Fix typo

petk: Remove unused variables

petk: Bump config.guess and config.sub

petk: Rename *.jpeg files to *.jpg

cmb69: Prevent race condition

petk: Remove ffi README in favour of docs

petk: Fix comment to match the future zts configuration option

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

docker-compose.ymlとDockerコンテナのPHPで環境変数を使用する

はじめに

これは個人的な備忘録になります。

docker-compose.ymlで環境変数を使用する

docker-compose.ymlがあるディレクトリ直下に、「.env」 を用意する。そのファイル内で定義した値を使用できる。

例えば、以下のように定義をした場合

.env
# REDIS関係
REDIS_PORT=6379
REDIS_PASSWORD=password

docker-compose.ymlでは、以下のように使用できる

docker-compose.yml
  redis:
    image: redis:alpine3.9
    command: redis-server --requirepass ${REDIS_PASSWORD}
    ports:
      - "${REDIS_PORT}:${REDIS_PORT}"

dockerコンテナで環境変数を使用する

dockerコンテナ内で環境変数を使用する場合は、docker-compose.ymlで定義する。

環境変数を1個〜2個指定する場合は、「environment」で定義をする。
以下のファイルでは、DATABASE_HOST/REDIS_HOSTを定義している。

docker-compose.yml
  app:
    build: ./app
    env_file: .env
    environment:
      DATABASE_HOST: db
      REDIS_HOST: redis
    depends_on:
      - db
      - redis
    volumes:
      - ./data/html:/var/www/html

また、複数指定したい場合は、「env_file」として、環境変数を記載しているファイルを指定する。

この時に、「.env」ファイルを使い回すことで、環境変数を「.env」ファイルに集約ができる。

PHPのコンテナでPHP.iniで注意点

PHP.iniでは、環境変数を使う、使わない、または有効にする変数の優先順位設定があります。

それが「variables_order」になります。デフォルトでは、「GPCS」となっていますので、環境変数は使えないです。

Dockerの環境変数が読み込めなくてハマりました。
「EGPCS」にすると、環境変数を優先して使ってくれます。

php.ini
; This directive determines which super global arrays are registered when PHP
; starts up. G,P,C,E & S are abbreviations for the following respective super
; globals: GET, POST, COOKIE, ENV and SERVER. There is a performance penalty
; paid for the registration of these arrays and because ENV is not as commonly
; used as the others, ENV is not recommended on productions servers. You
; can still get access to the environment variables through getenv() should you
; need to.
; Default Value: "EGPCS"
; Development Value: "GPCS"
; Production Value: "GPCS";
; http://php.net/variables-order
variables_order = "GPCS"

これでPHPのコード内で環境変数を使えるようになります。

$redis = new Redis();
$redis->connect($_ENV['REDIS_HOST'], $_ENV['REDIS_PORT']);

コードだけではなくて、PHP.iniの中でも環境変数は使えるようです。

php.ini
memory_limit=${PHP_MEMORY_LIMIT}

参考文献

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

ポートフォリオ「継続支援アプリ CHIRITSUMO!!」について

はじめに

はじめまして。
今回、PHPの基礎のアウトプットを兼ねてポートフォリオを作成しましたので、説明します。

目的

PHP言語を用いてフルスクラッチ開発をすることで、下記事項が理解できているかを確認する

・セッション
・GET送信、POST送信
・条件分岐、繰り返し処理
・DB関連(DB接続、SQL実行)
・DBデータの編集、画面への出力

スペック

■言語
PHP, HTML, CSS, JavaScript(jQuery)

■DBMS
MySQL

■フレームワーク
なし

■サーバー
XSERVER

ポートフォリオ

URL:http://chiritsumo.nyankormotti.com

サンプルユーザ
email:test@sample.com
pass:111111

ポートフォリオの概要

勉強時間、実施内容を記録するWEBサービス

ポートフォリオの機能

■ユーザー情報関連
・ユーザー登録
・ログイン・ログアウト
・ユーザープロフィール編集
・パスワード変更
・パスワードリマインダー
・退会

■メイン機能
・マイページ(実績一覧)
・実績登録
・実績編集
・実績削除
・実績詳細
・カテゴリー編集
・実績検索

■その他
・お問い合わせ

何ができるか

■実績を投稿できる
 (勉強した日にち、勉強時間、内容、内容の画像を保存できる。POST送信にて対応)
ezgif.com-video-to-gif.gif

■実績詳細にて保存した画像を拡大して閲覧できる(lightboxを使用)
ezgif.com-video-to-gif.1gif.gif

■実績をカテゴリーで検索、また実績日を範囲指定して検索できる。
実績登録した日にちの昇順、降順でソートを実施できる。
ページネーション後も検索情報を保持している。
(GET送信にて対応)
 ※多くのデータ数が必要なため、ユーザーを変更しています。
ezgif.com-video-to-gif3.gif

■その他
・パスワードリマインダーにて、登録されたメールアドレス宛に認証キー、新しいパスワードを送信する。

作成方法

1.機能の洗い出し

2.画面モックの作成
スクリーンショット 2019-05-12 21.24.00.png

3.テーブル設計、DB作成

4.各画面、機能を実装
ログイン、ユーザー登録機能などセッション周りから作成。
→パスワード変更など非機能要件
→POST・GET送信関連などのメイン機能を実装
→細部の調整

5.テスト
・各機能の処理が正常終了すること。
・商品一覧表示機能に関しては、境界値のデータを作成し、実施。
・URL直打ちした際にセッションが保持されているか確認。 など

工夫したところ

■検索条件の保持
実績詳細画面からマイページへ遷移する際や、ページングにてページを移動する際に、検索条件を保持するために、GET送信を用いています。
実績詳細画面から戻る際は、実績テーブルのキーであるIDのみGET送信から削除して遷移しています。(遷移時のURLにて「p_id」を削除しています)

■お問い合わせ機能
セッション情報の有無(ログイン前後)にて、お問い合わせ画面のメールアドレス入力フォームの表示・非表示を制御しています。
 (ログイン後はセッションIDよりDBからメールアドレスを取得し、メールを送信する仕様にしています。)

■マイページ画面の余白
マイページ画面の余白を確保するために、検索フォームをモーダルで出力するようにしています。
また、ヘッダーのメニューをドロップダウンにするようにして、空間を確保し、ゆとりを持たせています。
(実績一覧の表示にはcssのoverflow:scrollにてスクロールして表示しています。)

ポートフォリオの課題

・カテゴリー名変更機能の追加(登録、削除機能のみ)
・FWによるMVCモデルの適用(保守性が低い)
・SASSを用いたCSS実装(保守性が低い)
・レスポンシブ対応(1000px以下だと崩れる)

現在の学習内容(2019.05.12現在)

・Laravel
・JavaScriptの基礎
・React、Vue.js(主にVue.js)
・SASS
・CSS設計(FLOCSS)

→Laravelでポートフォリオ作成予定

最後に

Github: https://github.com/nyankormotti/CHIRITSUMO.git

 

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

ログイン認証について

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>display</title>
</head>
<body>
<?php
$dsn = 'xxxxxx';
$user = 'xxxxxx';
$password = 'xxxxxx';
try {
    // メアドとパスワードの入力チェック
    if (empty($_POST['mail']) || empty($_POST['pass'])) {
        echo  "メールアドレスかパスワードが入力されていません。";
    } else {
        //DB接続
        $dbh = new PDO($dsn, $user, $password);
        $stmt = $dbh->prepare("SELECT * FROM members where mail = :mail AND pass = :pass");
        $stmt->bindParam(':mail', $_POST['mail'], PDO::PARAM_STR);
        $stmt->bindParam(':pass', $_POST['pass'], PDO::PARAM_STR);
        $stmt->execute();
        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        //配列名前だけ表示
        }
        //レコードがない場合の表示
        echo "メンバーが存在しません。";
    }
} catch (PDOException $e) {
    exit ('データベース接続失敗。' . $e->getMessage());
}
?>
</body>

ひとまずはここまでできている。

あとはMySQLから引っ張ってきたレコードの名前を表示すれば終わりのはず。

配列を使って名前を表示するのだが、いまいちやりかたがわからず。

ぐぐるのみ。

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

PHPのアクセス修飾子: public, private, protected の使い分け

はじめに

アクセス修飾子が必要な理由として第一に保守の容易さに挙げられます.
オブジェクト志向のカプセル化を想像するとわかりやすいかもしれません.
チーム開発をしていて自分がクラスを作る際は基本的に, 他の人がそのクラスを使いやすいように、使って良い機能だけ公開し、使ってほしくない機能は隠します。
このようなシステムを作るときこのアクセス修飾子が役に立ちます.

アクセス修飾子

アクセス修飾子はpublic, protected, private の三つがあり, 下に行くほどアクセスできる範囲が狭くなります.

アクセス修飾子 意味
public 外部から参照できる
protected 変数、関数を宣言したクラスと継承されたクラスから参照できる
private 変数、関数を宣言したクラス内のみ参照できる

下記は説明のために作成したものです.
変数名にpublicなどをつけるという愚かな行為をしているため
コピペはしないでください

class Parent{
  //$public, #protected, $private全てアクセスできる
  public $public;
  protected $protected;
  private $private;

  //privateで読み込みだけしていい場合このように公開する
  public function getPrivate{ 
    return $this->pra;
  }
}

Mainを継承

子クラス
class Child extends Parent{
  // $privateはアクセスできない
  // $public, $protectedはアクセスできる
}
クラス外
//$private, $protected はアクセスできない
//$publicはアクセスできる

参照リンク

PHPでクラスを使う
TomoBlogの技術書

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

__debugInfo の隠れ仕様的なもの

__debugInfo の隠れ仕様的なもの

php 5.6 より __debugInfovar_dump の出力を弄れる様になってますが、その挙動についてドキュメントで触れられていないことがあるので少々補完します。
※ アンドキュメントってことは正しい仕様ではなく「現在たまたまそうなっているだけ」の可能性があります
※ 確認は全て手元の php 7.1.14 で行いました

おさらい

class Debug
{
    private   $privateField   = 1;
    protected $protectedField = 2;
    public    $publicField    = 3;
}

$debug = new Debug();
$debug->dynamicField = 4;

var_dump($debug);

このようなコードを実行すると下記のような出力が得られます。

class Debug#2 (4) {
  private $privateField =>
  int(1)
  protected $protectedField =>
  int(2)
  public $publicField =>
  int(3)
  public $dynamicField =>
  int(4)
}

このクラスにマニュアル通り__debugInfo を実装します。

class Debug
{
    private   $privateField   = 1;
    protected $protectedField = 2;
    public    $publicField    = 3;

    public function __debugInfo()
    {
        return [
            'propSquared' => $this->privateField ** 2,
        ];
    }
}

$debug = new Debug();
$debug->dynamicField = 4;

var_dump($debug);

出力は下記のようになります。

class Debug#2 (1) {
  public $propSquared =>
  int(1)
}

まぁ仕様どおりですね。

隠れた仕様1(アクセスレベル)

実際、上記のような完全カスタムの用途が多いと思いますが、私が今回やりたかったのは「でかいプロパティを伏せる」でした。
巨大フィールドを抱えていると var_dump の出力がでかすぎて視認性が悪いからです。
これはその過程で気づいた仕様です(private とかを維持したままカスタムする方法がわからなかった)。

ドキュメントに一切記載がないのですが、どうも __debugInfo の返り値はオブジェクトを配列キャストしたものであるべきのようです。

public フィールドを配列キャストしても普通のキーになるため、素の配列を返すと public と判定されます。上記で public $propSquared となっているのはそのためです。
つまり、それらしい配列を返してやれば __debugInfo で private/protected(っぽい)出力をすることができます。

    public function __debugInfo()
    {
        return [
            "\0Debug\0dummy1" => 'this is private',
            "\0*\0dummy2"     => 'this is protected',
        ];
    }

この出力は下記のようになり、あたかも dummy1 という private フィールドと dummy2という protected フィールドがあるかのような出力になります。

class Debug#2 (2) {
  private $dummy1 =>
  string(15) "this is private"
  protected $dummy2 =>
  string(17) "this is protected"
}

ここで冒頭に戻り、「でかい(特定)プロパティを伏せる」ためには配列キャストしてからそれらを伏せれば良いことが分かります。

    public function __debugInfo()
    {
        $properties = (array) $this;
        unset($properties["\0Debug\0privateField"]);
        return $properties;
    }
class Debug#2 (3) {
  protected $protectedField =>
  int(2)
  public $publicField =>
  int(3)
  public $dynamicField =>
  int(4)
}

それらしいキーを伏せているため、 $privateField が消えています。

隠れた仕様2(再帰参照)

再帰参照を含むオブジェクトで __debugInfo を実装すると出力がやべぇことになります。

class Debug
{
    public function __debugInfo()
    {
        return (array) $this;
    }
}

$debug = new Debug();
$debug->dynamicField = $debug;

var_dump($debug);

上記の出力は下記のようになります(長すぎるので抜粋)。

class Debug#2 (1) {
  public $dynamicField =>
  class Debug#2 (1) {
    public $dynamicField =>
    class Debug#2 (1) {
      public $dynamicField =>
      class Debug#2 (1) {
        public $dynamicField =>
                                      class Debug#2 (1) {
                                        ...
                                      }
      }
    }
  }
}

上記のインデントのズレは私のミスでもなんでもなく、本当に大量にネストされて遥か右方へ追いやられた結果です(前後は省略)。
なお、 __debugInfo を実装しなければこのようなことは起きません。

多分組み込みなら再帰の検出ができるけど、 __debugInfo を自前実装した結果、(配列なので)再帰の検出ができなくなってるのかな?(だとしても最終的に ... が出るのが謎い)。
__debugInfo を実装するときは再帰に注意するか、明示的な(シンプルな)配列を返したほうが良さそうです。

隠れた仕様3(print_r)

これもドキュメントにないのですが、 __debugInfo を実装すると print_r にも影響が出ます(https://github.com/php/php-src/blob/php-7.1.14/Zend/zend.c#L186)。

class Debug
{
    public function __debugInfo()
    {
        return ['field' => '__debugInfo の返り値です'];
    }
}

print_r($debug = new Debug());

実行すると下記のような出力になり、 print_r にも影響が出ていることが分かります。

Debug Object
(
    [field] => __debugInfo の返り値です
)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP】オブジェクト指向を学ぶ[その1]

オブジェクト指向

オブジェクト指向を学ぶために軽い自己紹介するコードを作ってみます。
まず
・class設計・・・設計図
・インスタンス ・・・もの
と言う考えを念頭におきます。

コード

index.php
<?php

//クラス定義
class Self_Introduction{

    // プロパティー
    // 変数定義
    private $name;
    private $age;

    // インスタンスが生成されると同時に処理が走る
    public function __construct($name, $age){
        $this->name = $name;
        $this->age  = $age;
    }

    // メソッド
    public function hello(){
        echo "私の名前は{$this->name}です。<br>年齢は{$this->age}才です。";
    }

}

// インスタンス生成
$user = new Self_Introduction("太郎", "35");

// メソッド呼び出し
echo $user->hello();

// 結果
// 私の名前は太郎です。
// 年齢は35才です。

classの中には、定数や変数そして関数 ("メソッド" といいます) を含めることができます。

解説

まずclassを定義します。
class名の一文字目は大文字にする習わしがあるみたいです。

このclassの中で変数を定義したりconstructを書いたりメソッドを書いたりします。

そして、$user = new class名(引数);とすることでclassを使うインスタンスと言うものを生成し、メソッドを呼び出すことで一連の流れは終了です。

インスタンス生成で何が起きているか

$user = new Self_Introduction("太郎", "35");この部分で何が起きているのか。

インスタンスが生成されると同時にclass内の__construct()に処理が走ります。
すると、インスタンスが生成された時の引数「("太郎", "35")」が__construct()で処理されます。

メソッド呼び出し

echo $user->hello();最後にメソッドを呼び出します。
$userはclass Self_Introductionを使ったインスタンスです。
Self_Introductionの中のhello();メソッドを使用しますと言った意味合いが近いと思います。

そして、メソッドに処理が走る結果として、自己紹介が行われると言った流れになります。

アクセス権について

3つのアクセス権があります。
public・・・どこからでもアクセス可能
private・・・クラスとサブクラスからアクセス可能
proected・・・クラスからアクセス可能

こちらを踏まえて以下のコードを見てみます。

index.php
class Access{

    public $public = "publicです";
    private $private = "privateです";
    protected $protected = "protectedです";

    function accessHello(){
        echo $this->public;
        echo $this->private;
        echo $this->protected;
    }
}

$hoge = new Access();
echo $hoge->public; //publicです
echo $hoge->private; //出力されません
echo $hoge->protected; //出力されません
$hoge->accessHello(); //publicですprivateですprotectedですと出力されます

実際インスタンスを生成してアクセスしてみるとこのような結果になります。
privateとpritectesdは外部からはアクセスできないので出力はされません。

ですがaccessHello()はどうでしょうか?
全てが表示されています。
どう言うことかというとprivateでもprotectedでも同じクラス内のメソッドの中で処理が書かれています。
そして、メソッド自体のアクセス権は何も記されていないのでpublicです。

なので外部でaccessHello()と呼び出すとクラス内で処理された結果が呼び出されるので、privateでもprotectedでも出力されるんですね。

次回はセッター、ゲッターについて書きます。

※何か間違っていること、これも覚えておいた方がいいと言うことがあれば是非教えてください

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