Open66

PHP-log

ピン留めされたアイテム
m0n0rem0n0re

はじめに

phpが売りの会社に入るかもしれないので、1からphpを学んでみる。

目標地点

phpの公式ドキュメントを一通りみて、基本的な仕組みと便利そうな関数とかを理解する

環境情報(適宜追加)

OS:Windows 10
PHP:version 8.2

m0n0rem0n0re

基本的な構文

https://www.php.net/manual/ja/language.basic-syntax.php

PHPタグ 開始タグと終了タグ

https://www.php.net/manual/ja/language.basic-syntax.phptags.php

PHPは開始タグ<?phpと終了タグ?>を探してこの中のコードを実行する。

<?php
...
?>

※短縮形の書き方もあるが省略(公式もできる限り<?php ... ?>を使えといっている。

ファイルがphpコードだけで構成されている場合は開始タグ<?phpだけのほうがいいらしい。
理由は終了タグ?>のあとに改行や空白があると出力バッファリング?というものが動いて意図せずその時点の内容を出力してしまうことがあるらしい。

// Laravelのファイルが<?phpしか書かれてなかったのはこれかあ。

m0n0rem0n0re

HTMLからの脱出

https://www.php.net/manual/ja/language.basic-syntax.phpmode.php

PHPのパーサは開始タグ<?php終了タグ?>に囲まれていない部分は無視する。
なので、HTMLの中にPHPコードを埋め込むことができる。

<p> ここはPHPは無視。ブラウザに表示されるよ</p>
<?php echo 'ここはPHPにパースされる' ?>
<p> ここもPHPは無視。ブラウザに表示されるよ</p>

でも条件式(if)を使うとHTMLタグをスキップしたりできる。

<?php if($hoge== true) ?>
条件がtrueなら表示されるよ
<?php else: ?>
条件がfalseなら表示されるよ
<?php end if; ?>
m0n0rem0n0re

コメント

PHPは3種類のコメントの書き方をサポートしてる。

<?php
// 単一行コメント

/*
複数行コメント
ここもコメントにできる
*/

# これも単一行コメント

?>

複数行コメントを入れ子にしようとするとおかしくなるので注意

<?php
 /*
    echo 'テストです'; /* このコメントが問題を生じます */
 */
?>
m0n0rem0n0re

型システム

PHPは部分型の関係を満たしつつ名前ベースで一致を調べる型システムを採用している。
//部分型?🤔
部分型はコンパイル時にチェックされる。型の検証は実行時に動的に行われる。

基本型

  • 組み込み型
    • ヌル(null)
    • スカラー型
      • 論理値(bool)
      • 整数(int)
      • 浮動小数点数(float)
      • 文字列(string)
    • 配列(array)
    • オブジェクト
    • リソース
    • never
    • void
    • クラス内での関係を表す相対型:self,parent,static
  • リテラル型
    • false
    • true
  • ユーザ定義型(クラス型という)
    • インターフェース
    • クラス
    • 列挙型(enum)
  • callable
m0n0rem0n0re

複合型

単一の型を組み合わせて、複合型を作ることができる。

交差型(intersection?)

https://tadtadya.com/php81-lang-types-intersection/

インターフェースの型チェックに使うことができる。
たとえば、引数に* インターフェースAとインターフェースB *を実装したクラスだけ受け取りたい…という定義をするには↓みたいにかける。

<?php

interface A;
interface B;

function test(A&B $class){}

union型

union型は、いずれかの型を受け入れる型を定義する。(日本語でおk)

<?php

float A;
array B;

function test(A|B $test){
...
}

この場合、test関数の引数にはfloatもarrayも渡せるようになる。

型のエイリアス

mixed という型のエイリアスがある。
これは「union 型 object|resource|array|string|float|int|bool|null 」すべてを受け入れるという型。

iterable

「Traversable|array」2つの型を受け入れる型。

Traversableとarrayについては以下参照か、別の章で出てきそう。

https://qiita.com/suin/items/3d52c8cf41636a1d8641

うーん、ここらへんの型宣言はちょっといぶし銀すぎる🤔

m0n0rem0n0re

NULL

https://www.php.net/manual/ja/language.types.null.php

null(ヌル)は「なんの情報も持っていないこと」を示す。
未定義の変数や、unset()されたものはnullになる。
// unset()は変数の割当を解除する関数

文法

nullは大文字小文字を区別しない。
// 個人的には小文字が好き。Nullとかはどうなるんだ?

<?php
 $var = null;
 $var = NULL;
?>

### 関数

is_null($hoge): $hogeがnullか調べる関数
unset($hoge):$hogeの割当を解除してnullにする関数 
m0n0rem0n0re

論理型(boolean)

bool型は true , false の2つの値を持つ。必ずこのどちらかしかできない。

文法

bool型にセットするとき大文字小文字は区別しない。

<?php
$foo = true;
>

booleanへの変換

boolに明示的に変換するときはキャスト(bool)を使う。
論理型が必要な場合は自動的にboolになるので一般的には不要らしい…。

以下の値をbool型にキャストする場合、すべてfalseとみなされる。

  • boolean の false
  • integer の 0 (ゼロ)
  • float の 0.0 および -0.0 (ゼロ)
  • 空の文字列 ""、 および文字列の "0"
  • 要素の数がゼロである 配列
  • unit 型 NULL (値がセットされていない変数を含む)
  • bool 型へキャストするように動作がオーバーロードされた内部オブジェクト。 例: 属性がない空要素から作 成された SimpleXML オブジェクト。

// boolへのキャストはあんまり使わないほうがよさそう。どっちかっていうと、意図せず↑になっちゃってバグになるとかのほうがありそうな…。

m0n0rem0n0re

整数

int は、ℤ = {..., -2, -1, 0, 1, 2, ...} という集合です。

ℤ = {..., -2, -1, 0, 1, 2, ...}について

🤔:?
🤖:整数(int)とは、0を中心に左右に無限に続く数字の集まりです。マイナスの数を含めることができるので、-2、-1、0、1、2、...という数がこの集まりに含まれます。数直線で表すと、中心に0があって、右に行くほど大きな数になり、左に行くほど小さな数になります。例えば、2という数は0から2つ右に進みますし、-3という数は0から3つ左に進みます。

🤔:Zってどういう意味?

🤖:"Z"というのは、ドイツ語の "Zahlen" (数) から来ており、整数の集合を表す数学用語の一つです。整数は、自然数や負の整数を含む数の集合であり、Zはそのような数の集合を表すためによく使われます。例えば、Zの中には、-2、-1、0、1、2などが含まれます。また、Zは整数の集合を表すときに、大文字で表記されることが多いです。

文法

int型は10進数、8進数、16進数、2進数の値を格納することができる。

$a = 1234; // 10進数
$a = 0123; // 8進数
$a = 0o123; // 8進数(8.1.0以降)
$a = 0x1A; // 16進数
$a= 0b11111111; // 2進数
$a = 1_234_567; // 10進数

整数のオーバーフロー

int型の範囲外を指定すると、floatとして解釈される。
32bit OSのオーバーフロー

<?php
$large_number = 2147483647;
var_dump($large_number);                     // int(2147483647)

$large_number = 2147483648;
var_dump($large_number);                     // float(2147483648)

$million = 1000000;
$large_number =  50000 * $million;
var_dump($large_number);                     // float(50000000000)
?>

64bit OSのオーバーフロー

<?php
$large_number = 9223372036854775807;
var_dump($large_number);                     // int(9223372036854775807)

$large_number = 9223372036854775808;
var_dump($large_number);                     // float(9.2233720368548E+18)

$million = 1000000;
$large_number =  50000000000000 * $million;
var_dump($large_number);                     // float(5.0E+19)
?>

// 環境によって許容値が異なる~~!🙄

除算

整数の割り算をそのまま行うことはできない(float型になるため)
整数の割り算をするならintdiv()を使う。

他の型からの変換

bool false -> 0、true ->1
float:小数点が丸められる。PHP8.1以降では精度が落ちると警告が表示される。
string: 文字列が数値形式の場合は対応する整数になる。そうでない場合は0になる。
null: 常に0になる
その他:未定義。現在は論理値に変換されたときに同じだが、動作が保証されないので使ってはいけない。

m0n0rem0n0re

浮動小数点数

文法

$a = 1.234;
$b = 1.2e3;
$c = 7E-10;
$d = 1_234.567; // PHP 7.4.0以降

floatへの変換

string:文字列が数値型文字列の場合は、対応するfloatに変換される。そうでない場合は0になる。
他の型:先にintに変換してからfloatに変換される。

floatの比較

floatの比較は色々むずかしいらしい。
ここがわかりやすかった。

https://www.codelab.jp/blog/?p=2162

とりあえずfloatの比較をするときは注意する!ってのは忘れないようにしたい。

NaN

浮動小数点演算の結果が、未定義のものや表現不可能な値になったとき、NaNと表示される。
NaNは何と比較してもfalseになる。
(NaNになった変数とNaNになった変数を比較するとさすがにtrueになる)

m0n0rem0n0re

文字列

文字が連結されたもの。
文字は1バイトなので256種類の文字しか扱えない(?)
これはPHPはUnicodeをネイティブサポートしていないためらしい。

what?🤔

🤖:この文章は、PHPがネイティブにUnicodeをサポートしていないということを伝えています。Unicodeは、世界中の多くの言語で使用される文字の標準化された集合を表すための規格であり、それぞれの文字に対して固有の符号を割り当てることができます。ただし、PHPでは、文字を1バイトで表現するため、256個の異なる文字しかサポートしていないため、Unicodeのすべての文字を表現することができません。Unicodeをサポートするためには、UTF-8などのUnicodeエンコーディングを使用する必要があります。

文字の上限

32bit環境だと文字列の最大長は2GB(2147483647バイト)。
64bit環境かつPHP7.0以降なら制限はない。

構文

文字列は4つの方法で定義できる。

m0n0rem0n0re

引用符(')

引用符で文字列をくくると、ほとんどのエスケープは使えなくなる。
シングルクォートを表すための\' と バックスラッシュを表す\\ だけ使える。

$str = 'this is a pen!';

二重引用符(")

二重引用符で文字列をくくると、エスケープを解釈するようになる。

$str = "this is a pen!";

使えるエスケープは以下の通り。

記述 説明
\n ラインフィールド(LF) 改行(Linux)
\r キャリッジリターン(CR) 改行(Mac)
\t 水平タブ (tab文字)
\v 垂直タブ
\e エスケープ(ESC)
\f フォームフィールド(FF)
\ バックスラッシュ
$ ドル記号
" 二重引用符
[0-7]{1,3} 正規表現にマッチする文字シーケンスは、8 進数表記の 1 文字です。 1 バイトに収まらない部分は、何もメッセージを出さずにオーバーフローします (そのため、"\400" === "\000" となります)。
\x[0-9A-Fa-f]{1,2} 正規表現にマッチする文字シーケンスは、16 進数表記の 1 文字です。
\u{[0-9A-Fa-f]+} 正規表現にマッチする文字シーケンスは、Unicode のコードポイントです。 そのコードポイントの UTF-8 表現を文字列として出力します。
m0n0rem0n0re

ヒアドキュメント

<<<{id}{改行}…{改行}{id}という形で書くと複数行の文字列の文章を作ることができる。
文章は二重引用符でくくったときと同じ動きをする。(エスケープや変数展開される)

<<<ID
ここにテキストを書ける
ID;

// PHP7.3ならこういうのも書ける
<<<ID
ここにテキストを書ける
 ここにテキストを書ける
  ここにテキストを書ける
   ここにテキストを書ける
   ID;

// こうしたらエラーになる
<<<ID
ここにテキストを書ける
 ここにテキストを書ける
  ここにテキストを書ける
   ここにテキストを書ける
ID;

Nowdoc

<<<'{id}'{改行}…{改行}{id}という形で書くと複数行の文字列の文章を作ることができる。
文章は引用符でくくったときと同じ動きをする。(エスケープされず、変数も展開されない)

<<<'LABEL'
ここにテキストを書ける
LABEL

変数のパース

二重引用符やヒアドキュメントであれば文字列に変数を使うとパースされる。

$hoge = "hello";

echo "$hoge world"; //->hello world!
echo "{$hoge} world!"; //-> hello world!

プロパティの展開もできる。

$juices = array("red","blue","org_color" => "green");

echo "this is {$juices[0]}"; // -> this is red
echo "this is {$juices[1]}"; // -> this is blue
echo "this is {$juices[org_color]}"; // -> this is green;

class human {
 public $name = "suzuki";
}

$human = new human();

echo "hi! {$human->name}!" -> hi! suzuki!
m0n0rem0n0re

複雑な波括弧構文

複雑な式を含めて書くことができる。

$great = 'fantastic';

// 動かないパターン
echo "This is { $great}; // -> エラーになる(変数の前に空白があるため)

// 動く
echo "This is {$great}; // -> This is fantastic

// 動く(クラス内プロパティ)を表示
echo "This square is {$square->width}00 centimeters broad." ;

// 動く(キーの文字列にクォートを使うときは波括弧を使う
echo "This works: {$arr['key']}";

// 動く 配列に添字を指定
echo "This works: {$arr[4][3]}";

// 動かない (fooが変数扱いになるので未定義になる)
echo "This works: {$arr[foo][3]};

// 動く (配列arr のキーfoo の3番目の要素)
echo "This works: ".$arr['foo'][3];

// 動く (オブジェクトobjのプロパティvalueの3番目が持つname)
echo "You can even write {$obj->values[3]->name}";

// 動く ($nameが'value'の場合、{$value}と同値になる)
echo "This is the value of the var named $name: {${$name}}";

// 動く(getNameの戻り値が 'Tanaka' の場合 {$value}>{Tanaka}?
echo "This is the value of the var named by the return value of getName(): {${getName()}}";

// 動かない
echo "This is the return value of getName(): {getName()}";

// 動かない { が\によってエスケープされているため
echo "C:\folder\{$great}.txt"

// 動く
echo "C:\\folder\\{$great}.txt"

文字列内で変数を使ってプロパティにアクセスもできる。

class foo {
 var $bar = 'I am bar.';
}

$foo = new foo();
$bar = 'bar';
$baz = array('foo' , 'bar' , 'baz' , 'quux');
echo "{$foo->$bar}"; // ->I am bar.
echo "{$foo->{$baz[1]}}; // ->I am bar.  baz[1]はbarなのでfooのbarにアクセスしてる。

class beers {
    const softdrink = 'rootbeer';
    public static $ale = 'ipa';
}

$rootbeer = 'A & W';
$ipa = 'Alexander Keith\'s';

// これは動作し、出力は I'd like an A & W となります
echo "I'd like an {${beers::softdrink}}\n";
//-> beers::softdrinkは rootbeer, {$rootbeer}となるので「A & W」が出力される

// これも動作し、出力は I'd like an Alexander Keith's となります
echo "I'd like an {${beers::$ale}}\n";
//-> beers->aleが「ipa」、{$ipa}となるので「Alexander Keith」が出力される
m0n0rem0n0re

文字列の文字単位でのアクセス

文字列が定義されている変数に対して添字で指定すると任意の文字を取得することができる。

// 文字列の最初の文字を取得します
$str = 'This is a test.';
$first = $str[0]; // ->T

// 文字列の 3 番目の文字を取得します
$third = $str[2]; // ->i

// 文字列の最後の文字を取得します
$str = 'This is still a test.';
$last = $str[strlen($str)-1];  // strlenで文字数を取得、添字は0から始まるので-1して末尾の文字を指す

// 文字列の最後の文字を変更します
$str = 'Look at the sea';
$str[strlen($str)-1] = 'e';
m0n0rem0n0re

文字列への変換

文字列へ変換するには(string)キャストや、strval()関数を使う。
echoprint を使うときなどは自動で文字列に変換される。

bool

trueは文字列の"1" 、falseは文字列の""(空文字)になる
//0じゃないんかーい!

数値->文字列

intやfloatはその数字が文字列となる。
浮動小数点数は指数表記になる。

配列

配列を文字列にするとArrayになる。中身を取り出したいときは$arr['foo']という形にする。

object

objectはマジック・メソッド__toStringを使う。

https://www.php.net/manual/ja/language.oop5.magic.php

リソース

リソースは"Resourve id #1"という文字列になる。1は実行中のPHPが勝手に割り振られる。
なので、この番号を前提でコードを書いてはいけない!
// てかリソースってなんや🤔

null

nullは常に空文字になる。

m0n0rem0n0re

数値形式の文字列

PHPの文字列は int や float と解釈できるときは数値とみなす。

$hoge = 1 + "105.5"; // -> "105.5"をfloatに変換して計算してくれるので 106.5になる。

PHP8.0以降では数値に変換できないとき、エラーとなるようになった。それより前だと、0になる。

// > ver8.0
$hoge = 1 + "my 10"; // -> エラー(PHP8.0以降のみ)
// < ver7.0
$hoge = 1 + "my 10"; // -> 1 ( "my 10"が0として扱われる)
m0n0rem0n0re

配列

https://www.php.net/manual/ja/language.types.array.php

PHPの配列は順番付けされマップ。値をキーに関連付けする。

array(
    key  => value,
    key2 => value2,
    key3 => value3,
    ...
)

構文

$array = array(
    "foo" => "bar",
    "bar" => "foo", //末尾にカンマはあってもなくてもOK
);

// 短縮形
$array =[
    "foo" => "bar",
    "bar" => "foo",
];


$array =[
    // キーの"8"はintにキャストされるので$array[8]で呼び出す。$array["8"]じゃないので注意
    "8" => "bar", 
 // キー"08"はキャストされないので$array["08"]で呼び出す。
    "08" => "foo",
 // "8.7"はintにキャストされ小数部分が切り捨てされる。つまり$array[8]で呼ぶ
  "8.7" => "foo",
   // boolもintになる。 trueは1、falseは0
 true => "foo",
   // null は空文字のキーになる。 $array[""]
   null => "foo",
   // arrayやobjectはキーとして使えない。
];

同じキーを指定するとどんどん上書きしていく。

$array = [
 1 =>     "a",
 "1" =>   "b",
 1.5 =>  "c",
 true => "d",
];

// 最終的には
$array[1] の中に "d"が格納されている状態になる。

文字列のキーと数値のキーを持つ配列を作ることもできる。

$array = array(
    "foo" => "bar",
    "bar" => "foo",
    100   => -100,
    -100  => 100,
);

Keyを省略することも可能。

$array = array("foo", "bar", "hello", "world");

一部だけキー指定もできる。
この指定をすると、array[0],array[1],array[6],array[7]に値が入る。

$array = array(
         "a",
         "b",
    6 => "c",
         "d",
);

角括弧構文による配列要素へのアクセス

配列の要素にアクセスするときは$array[key]と書く。

$array = array(
    "foo" => "bar",
    42    => 24,
    "multi" => array(
         "dimensional" => array(
             "array" => "foo"
         )
    )
);

$array["foo"] // -> "bar"
$array[42]; // -> 24
$array["multi"]["dimensional"]["array"]; // 配列の入れ子もできる
m0n0rem0n0re

配列のデリファレンス

デリンファレンス(dereference) 配列や文字列の中身を取り出すこと。
// PHPではリファレンスとは関係ないらしい…えぇ。

function getArray(){
  return array(1,2,3);
}

$secondElement = getArray()[1];
m0n0rem0n0re

角括弧構文で作成/修正

既存の配列を修正することができる。

$arr[key] =;
$arr[] =; // 非推奨

$arrが未定義またはnull、falseのときは新しく配列を作ってくれる。
$arrが文字列として使われているとき、[]がn文字目を取得する…という動きになるので注意。//なので非推奨

配列の値削除

unset($arr[5]);

配列を削除

unset($arr);
m0n0rem0n0re

配列の分解

配列はlist()を使って分解できる。


$source_array = ['foo', 'bar', 'baz'];

list($foo, $bar, $baz) = $source_array;
[$foo, $bar, $baz] = $source_array; // 省略形

echo $foo;    // "foo" を出力します。
echo $bar;    // "bar" を出力します。
echo $baz;    // "baz" を出力します。

多次元配列をforeachで回しながら分解するのにも使える。

$source_array = [
    [1, 'John'],
    [2, 'Jane'],
];

foreach ($source_array as [$id, $name]) {
    ...
}

変数の値を入れ替えたいとき、分解を使うと簡単にできる。

$a = 1;
$b = 2;

[$b , $a ] = [$a, $b];

echo $a; // -> 2
echo $b; // -> 1
m0n0rem0n0re

$foo[bar]はなぜ動かないのか

本来は$foo['bar']という形式で記述する必要がある。
しかし$foo[bar]も動作する。
なぜ動作するのか?

barが未定義の定数として扱われて、'bar'という文字列になるため。
これはPHP7.2.0以降では非推奨となり、E_WARNINGレベルの警告が発生する。
なので基本的には使っちゃだめ。

m0n0rem0n0re

配列への変換

int,float,string,bool,resourceは(array)にキャストするとarray[0]に変換元の値が格納されている配列が生成される。

$myInt = 10;
$array = (array) $myInt;
pirnt_r($array)

objectの場合は…

<?php
class A {
    private $B;
    protected $C;
    public $D;
    function __construct()
    {
        $this->{1} = null;
    }
}
var_export((array) new A());
array (
  '' . "\0" . 'A' . "\0" . 'B' => NULL,
  '' . "\0" . '*' . "\0" . 'C' => NULL,
  'D' => NULL,
  1 => NULL,
)

?🤔

m0n0rem0n0re

配列のアンパック

配列の前に...をつけると配列の値を展開することができる。(PHP7.4.0以降)

$arr1 = [1, 2, 3];
$arr2 = [...$arr1]; // [1,2,3]
$arr3 = [0, ...$arr1]; // [0, 1, 2, 3]
$arr4 = [...$arr1,  ...$arr2, 111] // [1, 2, 3, 1,2,3, 111]
m0n0rem0n0re

オブジェクト

オブジェクトの初期化

オブジェクトを作るときはnewを使う。

<?php

class foo{
  function fo_foo(){
     echo "foo を実行";
  }
}
$bar = new foo;
$bar->foo;

オブジェクトへの変換

オブジェクトがオブジェクトに変換される場合はなにも修正されない。
オブジェクト以外の型をオブジェクトにするときはstdClassというビルドインクラスのインスタンスが生成される。

<?php
$obj = (object) array('1' => 'foo');
var_dump(isset($obj->{'1'})); // PHP 7.2.0 以降は 'bool(true)' それより前は 'bool(false)'
var_dump(key($obj)); // PHP 7.2.0 以降は 'string(1) "1"' それより前は 'int(1)'
?>
m0n0rem0n0re

列挙型/ Enum

列挙型の基礎

列挙型は、クラスやクラス定数に対して更に制限を加えたもの。
型を定義して値を限定した集合を定義する。

enum Suit
{
  case Hearts;
  case Diamonds;
  case Clubs;
  case Spades;
}

function do_stuff(Suit $s)
{
   //...
}

do_stuff(Suit::Spades);
m0n0rem0n0re

リソース(Resource)

リソースは、ファイルやデータベースなどを保持する特別な型。
色々な種類がある。//多すぎぃ!
https://www.php.net/manual/ja/resource.php

リソースへの変換

リソースを他の型に変換することはできない。

リソースの開放

リソースがどこからも参照されなくなると自動的に削除される。
その後、ガーベジコレクタによって開放される。

持続的データベース接続はガベージコレクタによって破棄されない。

m0n0rem0n0re

Callable

コールバックはcallable型と呼ばれる。

call_user_func(),usort()などの関数は、関数を引数として渡すことができる。

受け渡し

function my_callback_function(){
  echo 'hello world';
}

class MyClass{
  static function myCallbackMethod(){
    echo 'Hello World!';
  }
}

// 単純なコールバック
call_user_func('myCallbackMethod');

// staticメソッドコール
call_user_func(array('MyClass', 'myCallbackMethod'));

// オブジェクトメソッドのコール
$obj = new MyClass();
call_user_func(array($obj, 'myCallbackMethod'));

// staticメソッドコール
call_user_func('MyClass:myCallbackMethod');

// 相対していによるstaticメソッドコール
class A {
  public static function who(){
    echo "A";
  }
}

class B extends A {
  public static function who(){
    echo "B";
  }
}

call_user_func(array('B', 'parent::who')); // A -> PHP8.2.0以降は非推奨

class C {
    public function __invoke($name) {
        echo 'Hello ', $name, "\n";
    }
}

//__invokeというのはこのクラスを関数みたいに呼べるようにする定義

$c = new C();
call_user_func($c , 'PHP!');  // Hello PHP!
m0n0rem0n0re

クロージャーを使ったコールバック

クロージャー?

🤖クロージャ(closure)とは、他の関数内で定義された無名関数(匿名関数)を指します。クロージャは、その関数の外側の変数(自由変数)にアクセスできるため、変数の値を保持したり、関数を呼び出すたびに変数を再定義する必要がない場合に便利です。

クロージャは、関数を返す高階関数として使われることが多く、PHPの場合、function() { ... }という構文で定義されます。クロージャを使用することで、より柔軟かつ効率的なコードを記述することができます。

$aisatsu = function($val){return $val;};
echo "おはよう、{$aisatsu('太郎')}さん";

// 結果:
//  おはよう、太郎さん

クロージャー(無名関数)を$aisatsuに格納する。その後変数を呼ぶような形で呼び出す

m0n0rem0n0re

Mixed

PHP8.0以降で利用可能な、object|resource|array|string|float|int|bool|nullの型を受け入れる型。

引数に色々な型を受け入れることができる関数の例

function test(mixed $data){
...
}
m0n0rem0n0re

Void

関数の戻り値がないことを示すための型。
union型には指定することができない。

m0n0rem0n0re

Never

never は関数が戻ってこないことを示す戻り値。
関数内でexit()や例外発生、無限ループに入ることを表す。

m0n0rem0n0re

クラス内での関係を示す相対型

self

self::は自クラスを指す(newしていない)
// $thisは自インスタンス(newしたもの)を指す

parent

parent:::は親クラスを指す。

static

static::は実行時に最も近い定義クラスを参照するために使う。
?🤔

m0n0rem0n0re

リテラル型

値の型だけでなく値そのものもチェックされる。
PHP8.0.0以降ではfalse型、PHP8.2.0以降ではtrue型がある。
これ以外にリテラル型は作ることができない。

m0n0rem0n0re

Iterable

Iterableはarray,Traversable型のエイリアス。

Iterable型はforeachなどでぐるぐる回ることができる。

ジェネレータ内でyield formすることができる。

ジェネレータ?

ジェネレータは配列やコレクションの要素を順番に返すことができるオブジェクト。
yieldが呼び出されるたびに処理が停止して値を返す。

function gen_numbers($start, $end) {
    for ($i = $start; $i <= $end; $i++) {
        yield $i;
    }
}

// ジェネレータを使って数字を順番に出力
foreach (gen_numbers(1, 10) as $number) {
    echo $number . " ";
}
// 出力結果:1 2 3 4 5 6 7 8 9 10

このときyieldが呼ばれるタイミングで値を返す。
gen_number() → yield 1が返す→ echo $numberで出力→gen_number()→yield 2が返す→…という形になる。

m0n0rem0n0re

変数

基本的なこと

PHPの変数は${任意}という形式で記述する。数字始まりはNG。

値渡し、参照渡し

通常は値渡し(bにaをセットしたあと、#bが変化しても$aは変化しない)

$a = 100;
$b = $a;
$a = 150;

echo $a // -> 150
echo $b // -> 100;

参照渡しするには代入するときにアンパサンドをつける。

$a = 100;
$b = &$a;
$a = 150;

echo $a // -> 150
echo $b // -> 150;
m0n0rem0n0re

定義済みの変数

https://man.plustar.jp/php/reserved.variables.html

スーパーグローバル

すべてのスコープで使用できる組み込みの変数。
以下がスーパーグローバルと呼ばれる定数。
$GLOBALS
$_SERVER
$_GET
$_POST
$_FILES
$_COOKIE
$_SESSION
$_REQUEST
$_ENV

m0n0rem0n0re

$GLOBALS

グローバルスコープで使用可能な変数への参照。

$GLOBALSにはグローバルスコープの変数が格納される。


$foo = "hi foo!";
echo $GLOBALS["foo"]; // -> hi foo!

グローバル変数を使うのは極力やめたほうがよいのであまり使わないかも…。
PHP8.1.0以降では$GLOBALSを書き換えることはできなくなった。

$GLOBALS = []; //$GLOBALSを新しい配列にする…(どうなるんだこれ)
$GLOBALS += []; // $GLOBALSに新しい要素を追加する
// etc...
m0n0rem0n0re

$_SERVER

サーバ情報および実行時の環境情報。

ヘッダ、パス、スクリプトの位置の情報を持っている配列。
この配列の中身はWebサーバが作ってくれる。
Webサーバによっては生成される内容が変化するため注意。

キーと説明
キー 説明
PHP_SELF 現在実行しているスクリプトのファイル名をドキュメントルートから取得する。
例:http://example.com/foo/bar.phpの場合は/foo/bar.phpが取得できる。
argv スクリプトに渡された引数の配列。
GETメソッドを通じてコールされた場合は検索引数が格納される。
argc スクリプトに渡されたコマンドライン引数の数。
GATEWAY_INTERFACE サーバのCGIバージョン。例:CGI/1.1
SERVER_SOFTWARE レスポンスヘッダ上に書かれているサーバの認識文字列。
SERVER_PROTOCOL ページがリクエストされた際のプロトコル名とバージョンです。
例.HTTP/1.0
REQUEST_METHOD ページにアクセスする際に使用されたリクエストのメソッド名です。 'GET', 'HEAD', 'POST', 'PUT' など。
REQUEST_TIME リクエストの開始時のタイムスタンプ。
REQUEST_TIME_FLOAT リクエストの開始時のタイムスタンプ (マイクロ秒までの精度)。
QUERY_STRING ページがアクセスされた際にもし検索引数があればそれが格納されます。
DOCUMENT_ROOT 現在実行されているスクリプトが存在するドキュメントルート ディレクトリです。サーバーのコンフィグレーションファイルで 定義されています。
HTTP_ACCEPT 現在のリクエストの Accept: ヘッダがもしあれば その内容。
HTTP_ACCEPT_CHARSET 現在のリクエストの Accept-Charset: ヘッダが もしあればその内容。例: 'iso-8859-1,*,utf-8'
HTTP_ACCEPT_ENCODING 現在のリクエストに Accept-Encoding: ヘッダが もしあればその内容。例: 'gzip'
HTTP_ACCEPT_LANGUAGE 現在のリクエストに Accept-Language: ヘッダが もしあればその内容。例: 'en'
HTTP_CONNECTION 現在のリクエストに Connection: ヘッダが もしあればその内容。例: 'Keep-Alive'
HTTP_HOST 現在のリクエストに Host: ヘッダが もしあればその内容。
HTTP_REFERER 現在のページに遷移する前にユーザーエージェントが参照していた ページのアドレス(もしあれば)。これはユーザーエージェントに よってセットされます。全てのユーザーエージェントが これをセットしているわけではなく、また、HTTP_REFERER を変更する機能を持つものもあります。 要するに、信頼するべきものではありません。
HTTP_USER_AGENT 現在のリクエストに User-Agent: ヘッダが もしあればその内容。ページにアクセスしてきているユーザーエージェント のしるしの文字列
HTTPS スクリプトが HTTPS プロトコルを通じて実行されている場合に 空でない値が設定されます。
REMOTE_ADDR 現在ページをみているユーザーの IP アドレス。
REMOTE_HOST 現在のページにアクセスしているホスト名。DNS の逆引き検索は ユーザーの REMOTE_ADDR に基づいています。
REMOTE_PORT ユーザーのマシンから Web サーバーへの通信に使用されているポート番号
REMOTE_USER 認証されたユーザー。
REDIRECT_REMOTE_USER リクエストが内部でリダイレクトされた場合の認証されたユーザー。
SCRIPT_FILENAME 在実行されているスクリプトの絶対パス。相対パスで呼ばれている場合は相対パスでの表記
SERVER_ADMIN Web サーバーの設定ファイルの SERVER_ADMIN (Apache の場合)ディレクティブ にセットされている値。スクリプトがバーチャルホスト上で 実行されている場合、バーチャルホストに対して値が定義されます。
SERVER_PORT Web サーバーの通信ポートとして使用されているポート番号。デフォルトでは '80' ですが、例えば SSL を使用している場合は セキュア HTTP ポートとして設定されている値に変わります。
SERVER_SIGNATURE サーバー上で生成されたページに追加される、 サーバーのバージョン名とバーチャルホスト名の文字列。 Web サーバーの設定で有効になっていることが必要です。
PATH_TRANSLATED バーチャルからリアルへのマッピングがなされた後の、 現在のスクリプトのファイルシステム上(ドキュメントルートではなく) でのパス。
SCRIPT_NAME 現在のスクリプトのパス。 スクリプト自身のページを指定するのに有用です。 FILE 定数には、カレント(すなわち読み込まれた)ファイルのパスとファイル名が 含まれます。
REQUEST_URI ページにアクセスするために指定された URI。例えば、 '/index.html'
PHP_AUTH_DIGEST HTTP ダイジェスト認証を 行っている場合、クライアントから送られた 'Authorization' ヘッダの 内容が設定されます(適切な認証処理を行うために利用します)。
PHP_AUTH_USER HTTP 認証しているときにそのユーザー名がセットされます。
PHP_AUTH_PW HTTP 認証しているときにそのユーザーの パスワードがセットされます。
AUTH_TYPE HTTP 認証しているときにその認証形式がセットされます。
PATH_INFO 実際のスクリプトファイル名とクエリ文字列の間にある、クライアントが提供するパス名情報。 たとえば、現在のスクリプトに http://www.example.com/php/path_info.php/some/stuff?foo=bar という URL でアクセスしていた場合の $_SERVER['PATH_INFO'] は /some/stuff となります。
ORIG_PATH_INFO PHP で処理される前の 'PATH_INFO' の原本。
m0n0rem0n0re

$_GET

HTTP GETリクエストのURLパラメータのキーと値を保持する。
URLがhttp://example.co.jp/?name=monoreのとき、```$_GET[''name]でmonore を取得できる。

m0n0rem0n0re

$_POST

HTTP POSTリクエストで渡されたデータのキーと値を保持する。

<form method="POST" action="sample.cgi">
	<p>お名前:<input type="text" name="NAME"></p>
	<p>メールアドレス:<input type="text" name="email"></p>
	<p><input type="submit" value="送信する"></p>
	<p><input type="reset" value="取消する"></p>
</form>
$_POST['NAME']=テキストボックスに入力した名前
$_POST['email']=テキストボックスに入力したメールアドレス
m0n0rem0n0re

$_FILES

HTTPファイルアップロード変数

アップロードされたファイルの情報を色々持つ。

キー 説明
$_FILES['userfile']['name'] クライアントマシンの元のファイル名。
$_FILES['userfile']['type'] ファイルの MIME 型。ただし、ブラウザがこの情報を提供する場合。 例えば、"image/gif" のようになります。 この MIME 型は PHP 側ではチェックされません。そのため、 この値は信用できません。
$_FILES['userfile']['size'] アップロードされたファイルのサイズ(バイト単位)
$_FILES['userfile']['tmp_name'] アップロードされたファイルがサーバ上のどこにあるか(テンポラリファイル)
$_FILES['userfile']['error'] ファイルアップロードに関するエラーコード
$_FILES['userfile']['full_path'] ブラウザからアップロードされたファイルのフルパス。ただし、実際のディレクトリ構造を反映してるとはいえないので信用できない値。(PHP8.1.0以降)
m0n0rem0n0re

$_SESSION

現在のスクリプトで使用できるセッション変数を含む連想配列。

そもそもセッションって…

セッションはウェブサイトやアプリケーションのユーザ側の状態を、サーバ側で保持するための仕組み。

  1. ユーザーがウェブサイトにアクセスすると、セッションIDがクッキーまたはURLパラメーターでユーザーのブラウザに保存されます。
  2. ユーザーがリクエストを送信するたびに、ブラウザはセッションIDをサーバーに送信します。
  3. サーバーは、受け取ったセッションIDに関連するセッションデータを検索し、必要に応じて変更します。
  4. セッションの最後に、サーバーはセッションデータを保存し、セッションIDをブラウザから削除します。

PHPはセッションを開始して、なんやかんやしてセッションを終了する…ということができる。

<?php
// セッション開始
session_start();

// セッションデータを保存
$_SESSION['username']='John';

//セッション終了
session_write_close();

//セッションを再開
session_start();

//セッションデータを読み取り
echo $_SESSION['username']; // -> John

//セッション終了
session_write_close();

m0n0rem0n0re

$_ENV

環境変数としてスクリプトに渡された変数の連想配列。
実行しているシェルから渡されるものが多いので列挙できないらしい。

m0n0rem0n0re

HTTPクッキー。
クッキーから渡された変数の連想配列。

Cookieってなんだっけ…?

CookieはWebサーバがWebブラウザに保存する小さなデータのこと。
WebサイトがユーザにCookieを送信するとブラウザはCookieを保存する。
次回ユーザが同じWebサイトにアクセスするとCookieをサーバに送ってWebサイト側でそのデータを利用する。
Cookieを消す操作やブラウザを変えるとCookieは消える。

m0n0rem0n0re

$php_erromsg

直近のエラーメッセージが保持されている。

m0n0rem0n0re

$http_responce_header

HTTPレスポンスヘッダが格納されている。

<?php
function get_contents() {
  file_get_contents("http://example.com");
  var_dump($http_response_header);
}
array(9) {
  [0]=>
  string(15) "HTTP/1.1 200 OK"
  [1]=>
  string(35) "Date: Sat, 12 Apr 2008 17:30:38 GMT"
  [2]=>
  string(29) "Server: Apache/2.2.3 (CentOS)"
  [3]=>
  string(44) "Last-Modified: Tue, 15 Nov 2005 13:24:10 GMT"
  [4]=>
  string(27) "ETag: "280100-1b6-80bfd280""
  [5]=>
  string(20) "Accept-Ranges: bytes"
  [6]=>
  string(19) "Content-Length: 438"
  [7]=>
  string(17) "Connection: close"
  [8]=>
  string(38) "Content-Type: text/html; charset=UTF-8"
}
m0n0rem0n0re

$argc

スクリプトに渡された引数の数。
スクリプトのファイル名は、常にスクリプトへの引数として渡される。
そのため$argcの最小値は1。

$argv

コマンドラインから実行したときスクリプトに渡された引数の配列。
最初の引数$argv[0]はスクリプトの名前なので、渡された値は[1]以降になる。

m0n0rem0n0re

マジック定数

使われる場所によって変化する定数(マジック定数)というものがある。
この定数はコンパイル時に解決される。また大文字小文字を区別しない。

名前 説明
LINE ファイル上の現在の行番号。
FILE ファイルのフルパスとファイル名 (シンボリックリンクを解決した後のもの)。 インクルードされるファイルの中で使用された場合、インクルードされるファイルの名前が返されます。
DIR そのファイルの存在するディレクトリ。include の中で使用すると、 インクルードされるファイルの存在するディレクトリを返します。 つまり、これは dirname(FILE) と同じ意味です。 ルートディレクトリである場合を除き、ディレクトリ名の末尾にスラッシュはつきません。
FUNCTION 関数名。無名関数の場合は、{closure}
CLASS クラス名。 クラス名には、そのクラスが宣言されている名前空間も含みます (例 Foo\Bar)。 トレイトのメソッド内で CLASS を使うと、 そのトレイトを use しているクラスの名前を返します。
TRAIT トレイト名。 トレイト名には、宣言された名前空間も含みます (例 Foo\Bar)。
METHOD クラスのメソッド名。
NAMESPACE 現在の名前空間の名前。
ClassName::class 完全に修飾されたクラス名。
m0n0rem0n0re

演算子

演算子の優先順位

演算子ごとに優先順位がある。
同じ優先順位のものがあるとき、左側から処理されるのか、右側から処理されるのかは演算仕事によって異なる。

https://man.plustar.jp/php/language.operators.precedence.html

m0n0rem0n0re

算術演算子

名前 結果
+$a 同一 $aをint や floatに変換する
-$a 負にする $aの逆
$a + $b 加算 $aと $bの合計
$a - $b 減算 $aと $bの差
$a * $b 乗算 $aと $bの積
$a / $b 除算 $aおよび $bの商
$a % $b 剰余 $a を $b で割った余り
$a ** $b 累乗 $a の $b の乗
m0n0rem0n0re

代入演算子

代入(値渡し)

$a = 3; // $a に 値3を代入する
$a += 5; // $a+5 の結果を $a に代入する
$b = "hello"; // $b に 文字列helloを代入する
$b .= "there!"; // $b . "there!"と同じ。 

参照渡し

$a = 3;
$b = &$a; // $b は $a への参照です

print "$a\n"; // 表示: 3
print "$b\n"; // 表示: 3

$a = 4; // change $a

print "$a\n"; // 表示: 4
print "$b\n"; // 表示: 4
              // $b の参照先は $a であり、その値が変わったからです
m0n0rem0n0re

ビット演算子

名前 説明
$a & $b ビット積 $a と $bの論理和をとる
$a | $b ビット和 $a と $bの論理積をとる
$a ^ $b 排他的論理和 $a と $b の排他的論理和をとる
~ $a 否定 ビットを反転する
$a << $b 左シフト $a のビットを左に $b ビットシフトする
$a >> $b 右シフト $a のビットを右に $b ビットシフトする
m0n0rem0n0re

比較演算子

名前 説明
$a == $b 等しい $a と $b が等しいときにtrue
$a === $b 等しい $a と $b が同じ型で等しいときにtrue
$a != $b 等しくない $a と $b が等しくないときにtrue
$a <> $b 等しくない $a と $b が等しくないときにtrue
$a !== $b 等しくない $a と $b が同じ型でなく、等しくないときtrue
$a < $b より少ない $a が $b より少ないときにtrue
$a > $b より多い $b が $a より多いときにtrue
$a <= $b より少ないか等しい $a が $b より少ないか等しいときtrue
$a => $b より多いか等しい $b が $a より多いか等しいときtrue
$a<=> $b 宇宙船演算子 a < $b の場合:-1、a == b の場合:0、a > $b の場合:1
m0n0rem0n0re

エラー制御演算子

PHPの式の前に付けた場合、その式により生成されたエラーメッセージは無視される。

/* 意図的なエラー */
$my_file = @file ('non_existent_file') or
    die ("Failed opening file: error was '" . error_get_last()['message'] . "'");

// この演算子は関数だけでなく、全ての式で動作します。
$value = @$cache[$key]; 
// インデックス $key が存在しない場合でも、警告を発生しません。
m0n0rem0n0re

加減子/減算子

https://www.php.net/manual/ja/language.operators.increment.php

いわゆるインクリメント・デクリメント。
プラスとマイナス記号を前に書くか、後ろに書くかで動きが若干異なる

名前 説明
++$a 前置加算子 a に 1を増やしてからaを返す(増えた値が返る)
$a++ 後置加算子 a を返してからaを増やす($aの値そのまま返る)
--$a 前置減算子 a から 1を減らしてからaを返す(減った値が返る)
$a-- 後置減算子 a を返してからaを減らす($aの値そのまま返る)

文字列に対しても使えるが文字コードによって返ってくる文字が違うのであんまり使わないほうがいいかも…。

m0n0rem0n0re

論理演算子

https://www.php.net/manual/ja/language.operators.logical.php

名前 説明
$a and $b 論理積 $a と $b が true の場合 true
$a or $b 論理和 $a と $b のどちらが true の場合 true
$a xor $b 排他的論理和 $a と $b のどちらかが true かつ 両方とも trueでないとき true
!$a 否定 $a が trueでないとき true
$a && $b 論理積 $a と $b が true の場合 true、$aがfalseのときは$bは評価しないためちょっと軽い
$a ||$b 論理和 $a と $b のどちらかが true の場合、true。$aが false のときは$bを評価しないためちょっと軽い

and ,or の方が && || より優先度が高い。

m0n0rem0n0re

配列演算子

名前 結果
$a + $b 結合 $a と$b を結合する
$a == $b 同等 $aと$bのキーとペアが等しい場合trueを返す
$a ===$b 同一 $aと$bのキーとペアと並び順とデータ型が一致する場合true
$a != $b 等しくない $a と $b が等しくないとき true
$a <> $b 等しくない $a と $b が等しくないとき true
$a !== $b 同一でない $a が $b と同一でない場合に true。

結合と同等と同一は便利そう

m0n0rem0n0re

型演算子

instansofを使うとその変数の型が一致するかどうか調べることができる。

class MyClass{}
classs NotMyClass{}

$a = new MyClass;

var_dump($a instance of MyClass); // -> bool(true)
var_dump($a instance of NotMyClass) // ->bool(false)

特定のクラスを継承しているか、親クラスも調べることができる

class ParentClass{}

class MyClass extends ParentClass{}

$a = new MyClass;

var_dump($a instanceof MyClass); // -> bool(true)
var_dump($a instanceof ParentClass); // -> bool (true)

interfaceも調べることができる

interface MyInterface{}

class MyClass implements MyInterface{}

$a = new MyClass;

var_dump($a instanceof MyClass); // -> bool(true)
var_dump($a instanceof MyInterface); // ->bool(true)