# PHP

# 基本事項

コマンドラインで php ファイルを実行

php test.php

デバッグ用出力

print_r(); // 簡易
var_dump(); // 詳細

# Basic Syntax

  • <?phpではじめて、?>で終わる。終わりのタグは、可能であれば省略する。
  • 命令文の最後には;が必ず必要。ただし終了タグの直前においては省略も可能。
// echoのショートハンド
<?php echo 'hello world' ?>.
<?= 'hello world' ?>

// comment1
# comment2
/*
* comment3
*/

# Types

# 概要

  • scalar(数学) types
    • boolean
    • integer
    • float(=double)
    • string
  • compound types
    • array
    • object
    • callable
    • iterable
  • special types
    • resources
    • NULL
  • pseudo types
    • mixed
    • number
    • callback
    • array|object
    • void

# Type の確認方法

  • var_dump(123) タイプと値をコンソール出力する
  • gettype(123) タイプを文字列として取得する(デバッグ用)
  • is_type(123) その型かどうかを判定したいときにつかう
var_dump(123); // => int(123)
echo gettype(1); // => integer

if (is_int(1)) {};
if (is_string('a')) {};

# boolean

真偽値。case-insensitive である。

if ($action == "show_version") {}

$is_valid = true;
if ($is_valid) {}

# echo

boolean を echo (文字列に Cast)すると、true は 1 を出力し、false は何も出力しない。

# キャスト

キャストしたいときは(bool)を使う。他のタイプでも同じだが、殆どの場合で自動キャストされるので、使うことはほぼない。

var_dump((bool) '1');

# FALSE として判定されるもの

  • FALSE
  • 0(integer)
  • 0.0(float)
  • 空文字列及び"0"(string)
  • 長さのない array
  • NULL

# TRUE として判定されるもの

  • 上記以外のすべて(resource と NAN を含む)

# Integer

整数。

$a = 1234; // 10進数 正の整数
$a = -123; // 10進数 負の整数
$a = 0123; // 8進数
$a = 0x1A; // 16進数
$a = 0b11111111; // 2進数

# float への変換

計算結果が integer の範囲を超える場合は自動的に float が返される。

$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)

計算結果が小数になる場合も float が返される。なお、round()は四捨五入、(int)は 0 に近い方に切り捨てる。

var_dump(25/7);         // float(3.5714285714286)
var_dump((int) (25/7)); // int(3)
var_dump(round(25/7));  // float(4)

# int への cast

  • boolean

    • true は 1
    • false は 0
  • float

    • 0 に近い方にまるめられる
  • string

    echo (int) "10.5"; // 10
    echo (int) "-1.3e3"; // -1300
    echo (int) "bob-1.3e3"; // 0
    echo (int) "bob3"; // 0
    echo (int) "10 Small Pigs"; // 10
    echo (int) "10.2 Little Piggies"; // 10
    echo (int) "10.0 pigs "; // 10
    echo (int) "10.0 pigs "; // 10
    

# Float

float = double = real numbers

$a = 1.234;
$b = 1.2e3;
$c = 7E-10;

# float へのキャスト

  • string

    echo (float) "10.5"; // 10.5
    echo (float) "-1.3e3"; // -1300
    echo (float) "bob-1.3e3"; // 0
    echo (float) "bob3"; // 0
    echo (float) "10 Small Pigs"; // 10
    echo (float) "10.2 Little Piggies"; // 10.2
    echo (float) "10.0 pigs "; // 10(float)
    echo (float) "10.0 pigs "; // 10(float)
    

# String

文字列には4種類の記法がある。

  • single quoted
  • double quoted
  • heredoc syntax
  • nowdoc syntax

# single quoted

  • 複数行に渡って書ける
  • 'を出力する時のみエスケープが必要
  • 制御文字は使えない
  • 変数は展開されない
  • 基本的にそのまま文字列として出力される
// 複数行書ける
echo 'You can also have embedded newlines in
strings this way as it is
okay to do';

// 'を出力するには\でエスケープ
echo 'Arnold once said: "I\'ll be back"';

// 下記はただの文字列として出力される
echo '$some_val with \r newline';

# double quoted

  • 複数行に渡って書ける
  • \を使って制御文字を出力できる
  • 変数は展開される
echo "$some_val with \r newline
and multiline
is ok";

# Nowdoc

  • single quote の別の書き方。
  • 中身は評価されない
  • 'EOT'の部分をシングルクオートで囲むこと。名前は任意に書き換えて OK。
echo <<<'EOT'
My name is "$name". I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}.
This should not print a capital 'A': \x41
EOT;

# Heredoc

  • double quote の別の書き方。
  • 中身が評価される
  • EOTの部分をダブルクオートで囲むか、もしくは囲まないこと。名前は任意に書き換えて OK。
$a = 'John';
$str = <<<EOT
my name is $a \r Doe
EOT;

# 変数のパース - simple syntax

double quoted 等の中において変数をパースする方法は、simple と complex の 2 種類がある。simple-syntax では、$を使う。変数名の区切りをはっきりさせる必要があるときは変数名を{}で囲む。

echo "my name is $myname. nice to meet you";
echo "my name is ${myname}. nice to meet you";
echo "$people->john drank some $juices[0] juice.".PHP_EOL;

# 変数のパース - complex syntax

複雑な Expression を書ける方法、という意味で Complex と呼ばれている。{}を使う。下記のような場合に使用する。

  • シングルクオートを使いたい
  • 動的に変数名を設定したい
  • Object のプロパティ名の区切りを明示したい
echo "This is {$arr['foo']}";
echo "This is ${$great}";
echo "This square is {$square->width}00;

# ブラケットによるアクセス

文字列の特定の場所にアクセスしたいときはブラケット[]もしくは braces{}を使う。2 文字以上を操作したいときは、substr()orsubstr_replace()を使う。UTF に対応していないので実際は使い物にならない。

'string'[0]; // => 's'
'string'[-2]; // => 'n'

# 結合

文字列は.で結合できる。

echo "my name "."is"." android";

# String への Cast

(string)orstrval()で文字列にキャストできる。echoprintfunction では自動的にキャストが行われる。

array, object, resources はそのままキャストしても意味がない("Array"などになってしまう)ので、print_r()var_dump()を使うこと。

  • boolean
    • true は"1"に、false は""になる
  • integer, float
    • そのまま文字列になる
  • array
    • "Array"という文字列になる
    • echo などしたいときは[]で中の要素を取り出して表示すること
  • object
    • __toStringに実装されている値になる
  • resouces
    • "Resource id #1"のような文字列になる。数字の部分は一意のリソースナンバーを指す。
  • NULL
    • ""になる

なお、php で使うほとんどの値はserialize()を使うことで string の表現に変換できる。シリアライズ化した値は、unserialize()でもとに戻すことができる。

# Arrays

PHP の Array は、実際は Ordered Map(key-value ペア) である。下記のような用途に使うことができる。

  • array
  • list(vector)
  • hash table
  • dictionary
  • collection
  • stack
  • queue

# array()による作成

  • キーには integer 又は string を使うことができる
  • value にはあらゆる値を格納できる
print_r(array(123, 456));
// => Array ( [0] => 123 [1] => 456 )

print_r(array(
    "foo" => "bar",
    "bar" => "foo", // trailing commaが使える
));
print_r([ // PHP 5.4以降では[]も使える
    "foo" => "bar",
    "bar" => "foo",
]);
// => Array ( [foo] => bar [bar] => foo )
  • キー名は、次のルールによりキャストされる
    • Valid な 10 進数を含む String は integer に
    • float は trunc された integer に
    • boolean は integer に
    • null は""(empty string)に
  • なお、array と object は key として使用することはできない
  • キーを省略すると、Auto Increment な integer が順に振られる。この際、その配列において過去に一度でも使われた数字は、すでに配列から消去されている場合でも、再利用はされない。再利用したい場合はarray_values()を使って reindex する作業が必要。
$array = array(
         "a",
         "b",
    6 => "c",
         "d",
);
/*
array(4) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "b"
  [6]=>
  string(1) "c"
  [7]=>
  string(1) "d"
}
*/
  • 要素へのアクセスは[]or{}をつかう。なお、この 2 つの記法は全く等価である。
var_dump($array["foo"]);
var_dump($array[42]);
var_dump($array{42});
var_dump($array["multi"]["dimensional"]["array"]);

# []による作成・変更

  • []で特定の要素を作成、取得、変更できる
  • もし$arrが存在しなかった場合は作成される(Array 作成の方法としては非推奨)
  • Key を省略した場合は、Auto Increment な数値が自動で振られる。
$arr[] = 56;
$arr["x"] = 42;
// Array([0] => 56, [x] => 42)

# Array に関連した便利なファンクション

Array Function の一覧 (opens new window)

  • unset($arr), unset($arr[key]) 要素又は配列を削除する。reindex は行わない。

    $arr = array(5 => 1, 12 => 2);
    
    $arr[] = 56;    // $arr[13] = 56;
    $arr["x"] = 42;
    unset($arr[5]); // This removes the element from the array
    unset($arr);    // This deletes the whole array
    
  • array_values($arr) reindex した配列を返す

  • foreach ($array as $value) {}

  • foreach ($array as $key => $value) {}

  • count($arr)

  • sort($arr)

  • array_diff($arr1, $arr2)

# String へのキャスト時の注意

key のタイプによってキャスト時の作法が変わる

// Keyが変数のとき
echo "$array[$i]"; // ""で囲む

// KeyがStringのとき
echo "{$array['test']}"; // complex-syntaxを使う
echo $array['test']; // 又は""の外に出して、`.`でconcatして対応する

# Array へのキャスト

  • (array) somevalで Array にキャストできる。

  • int, fload, string, boolean, resource の場合、array(someVal)したのと同じことになる。つまり、長さ 1 の配列に、someVal が格納される。

    print_r((array) 123); // => Array([0]=>123)
    
  • NULL の場合、長さが 0 の配列になる。

  • object の場合

    • プロパティがキー名になる
    • private の場合は\0クラス名\0プロパティ名になる
    • protected の場合は\0*\0プロパティ名になる
    • \0は null を表す。なぜこれが必要なのかはよくわからない。
    class MyClass
    {
      public $myPublic;
      private $myPrivate;
      protected $myProtected;
    }
    /*
      array(3) {
        ["myPublic"]=>  NULL
        ["\0MyClass\0myPrivate"]=>  NULL
        ["\0*\0myProtected"]=>  NULL
      }
    */
    

# 配列の比較

array_diff($arr1, $arr2)により、arr1 に存在し、arr2 に存在しない要素を抽出できる。

$array1 = array("a" => "green", "red", "blue", "red");
$array2 = array("b" => "green", "yellow", "red");
$result = array_diff($array1, $array2);
// => Array([1] => blue)

# 参照渡しと値渡し

Array の場合、デフォルトは値渡しになる。参照渡しにしたい場合は&を付与する。

$arr1 = array(2, 3);
$arr2 = $arr1;
$arr2[] = 4; // arr1は変更されていない
$arr3 = &$arr1;
$arr3[] = 4; // arr1は変更されている

# Iterables

PHP 7.1 以降で使える疑似タイプ。下記を受け付ける。foraech することができる。

  • array
  • Traversable interface を備えた Object
function arr(): iterable
{
    return [1, 2, 3];
}
function gen(): iterable
{
    yield 1;
    yield 2;
    yield 3;
}

foreach (arr() as $value) {}
foreach (gen() as $value) {}

# Objects

object = クラスインスタンスのこと。

class Dog
{
    public function bark()
    {
        echo "bow!";
    }
}

$dog = new Dog;
$dog->bark();

# object へのキャスト

  • object へキャストした場合は、stdClassというビルトインクラスを基にしたインスタンスが作成される。

  • NULL はプロパティを持たないインスタンスに変換される

    var_dump((object) null);
    /*
    object(stdClass)#1 (0) {}
    */
    
  • Array は、key-value がそのまま property-value に変換される。

    $arr = [
        "name" => "john",
        "age" => 33,
    ];
    var_dump((object) $arr);
    /*
    object(stdClass)#1 (2) {
      ["name"]=> string(4) "john"
      ["age"]=> int(33)
    }
    */
    
  • int や string など、scalar な値は、scalarというプロパティに格納される。

    var_dump((object) 123);
    /*
    object(stdClass)#1 (1) {
      ["scalar"]=> int(123)
    }
    */
    

# Resources

# null

変数が値を持っていないことを示す。

  • null を明示的にセットした変数
  • まだ一度も値がセットされていない変数
  • unset()された Key 又は Array

# null へのキャスト

昔は(unset)が使えたが、今は強く非推奨。

# Callbacks / Callables

call_user_func() or usort()など、いくつかのファンクションは、コールバックを受け取ることができる。 コールバックの渡し方は下記の 4 つがある。

  • 文字列で渡す方法
  • array で渡す方法
  • object を渡す方法
  • Anonymous Function を渡す方法

# シンプルな関数をコールバックに指定

function myCallbackFunction($text = "")
{
    echo 'hello world!'.$text;
}
call_user_func('myCallbackFunction');
call_user_func('myCallbackFunction','hello2');

# クラスメソッド、インスタンスメソッドをコールバックに指定

注意:JS と異なり、PHP ではクラスメソッドをインスタンスを起点にして呼ぶことができる。

// An example callback method
class MyClass
{
    public static function myCallbackMethod()
    {
        echo 'Hello World!';
    }
}

// Static class method call
call_user_func('MyClass::myCallbackMethod');
call_user_func(array('MyClass', 'myCallbackMethod')); // old fasion

// Object(instance) method call
$obj = new MyClass();
call_user_func(array($obj, 'myCallbackMethod'));

# 親クラスのメソッドをコールバックに指定

class MyChildClass extends MyClass
{
    public static function myCallbackMethod()
    {
        echo "some message";
    }
}

call_user_func(array('MyChildClass', 'parent::myCallbackMethod')); // => Hello World!

# __invokeを実装しているクラスのインスタンスをコールバックに指定

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

$c = new MyInvokableClass();
call_user_func($c, 'PHP!');

# Closure

Closure = Anonymous function のこと。

// closure
$double = function ($a) {
    return $a * 2;
};
$new_numbers = array_map($double, [1,2,3,4,5]);
// => 2,4,6,8,10

# Pseudo-types

PHP のドキュメントにおいて、説明の便宜上、定義しているタイプのこと。引数のタイプや値を正しく説明するための架空のものであり、実際の PHP のプリミティブタイプとして存在するわけではない。

# mixed

いくつかのタイプを受け取る事ができるタイプ。例)gettype()

# number

integer + float

# callback

callable のこと。callable が登場する以前は、callback という擬似タイプが存在していた。

# array|object

array もしくは object

# void

何もリターンしない、何も引数として受け付けない、というタイプ。PHP7.1 以降ではリターンタイプとして使える。

# 型の相互変換

# 自動変換

PHP の方は、文脈によって自動的に決定される。例えば乗算演算子では、下記のように型が自動変換される。

オペランドのいずれかが オペランドの評価 結果
float を含む すべて float float
float を含まない すべて integer integer

# キャストの種類

  • (int), (integer) - 整数へのキャスト
  • (bool), (boolean) - 論理値へのキャスト
  • (float), (double), (real) - float へのキャスト
  • (string) - 文字列へのキャスト
  • (array) - 配列へのキャスト
  • (object) - オブジェクトへのキャスト
  • (binary) - バイナリへのキャスト
  • (unset) - NULL へのキャスト (強く非推奨)

# Variables

# Basics

  • 命名規則 →\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*

  • 値の代入

    • デフォルトではすべて値渡し。Object についても、handle(object の実体への参照のようなもの)を値渡ししている。
    • 参照渡ししたい場合は、代入する値に&を使う。これにより エイリアス (同じ向き先を持つ変数)が作成される。
    • &をつけることができる対象は、名前付き変数のみ(&(1+2)などは無効)
    $a = 1;
    $b = $a;
    $b = 2;
    var_dump($a); // => 1
    

# Predefined Variables

PHP には多くの定義済み変数 (opens new window)がある。特に、Superglobals と呼ばれる下記のものは、プログラムのどこからでも、なんの手続きもせずに使用することができる。

  • $GLOBALS
  • $_SERVER
  • $_GET
  • $_POST
  • $_FILES
  • $_COOKIE
  • $_SESSION
  • $_REQUEST
  • $_ENV

# Scope

スコープの種類は、グローバルか、ローカル(ファンクション内)の 2 つ。

# Include

他のファイルを Include した場合、Include した場所にそのファイルを差し込んだようなイメージになる。

  • $aは、other.php内で使用可能
  • other.php内の変数・メソッドは、取り込み主で使用可能。スコープは、include文が存在している場所によって決まる。ただし、ファンクションとクラスはグローバルスコープになる。詳細はこちら (opens new window)
$a = 1;
include 'other.php';

# グローバル変数とローカル変数

ファンクションの中からアクセスできるのはローカル変数のみ。

$a = 1; // グローバル
function test()
{
    echo $a; // ローカル変数を参照する。グローバルにはアクセスできない。
}

# global キーワードを使ってグローバルにアクセス

$a = 1;

function Sum()
{
    global $a;
    echo $a; // グローバルにアクセスできる
}

# $GLOBALS を使ってグローバルにアクセス

$a = 1;

function Sum()
{
    echo $GLOBALS['a'];
}

# static 変数

static 変数を使うと、ファンクションの終了後も値を保持しておくことができる。

function test()
{
    static $a = 0;
    echo $a;
    $a++;
}
test(); // 0
test(); // 1
test(); // 2

static 変数を使って再帰処理を書くとこんな感じ。

function test()
{
    static $count = 0;

    $count++;
    echo $count;
    if ($count < 10) {
        test();
    }
}

# References with global and static variables

TODO: 意味不明

# Variable Variables

動的に指定できる変数名のこと。

$a = 'hello';
$$a = 'world';

echo "$a $hello"; // hello owrld
echo "$a ${$a}"; // hello world

配列で使う場合は、あいまいさを{}で解消する必要があるので注意。

$$a[1] // invalid as it's ambiguous
${$a[1]} // ok
${$a}[1] // ok

クラスのプロパティに動的にアクセスしたいときは、変数や、{}を使うことができる。

class foo
{
    public $bar = 'I am bar.';
    public $r = 'I am r.';
}
$foo = new foo();
$name = 'bar';
$names = array('foo', 'bar');

echo $foo->$name . "\n"; // I am bar.
echo $foo->{$names[1]} . "\n"; // I am bar.
echo $foo->{'b' . 'ar'} . "\n"; // I am bar.
echo $foo->{'arr'[1]} . "\n"; // I am r.

# Variables From External Sources

# フォームで送られてきた値の取得

使うことはなさそう。必要になったら学習 (opens new window)する。

$_POST['username']; // POSTのbodyのみ取得
$_REQUEST['username']; // POSTのbodyと、Queryも取得

# Cookies

  • setcookie()で値をセット
  • $_COOKIEで値を取得
// 下記のように配列「風」にしておけば、取り出す際に自動で配列にしてくれる
setcookie('mycookie[0]', 'mydata-1');
setcookie('mycookie[1]', 'mydata-2');

var_dump($_COOKIE);

# ドットの扱い

外部から取得したデータの変数名(Key など)にドットが含まれている場合、PHP では変数名にドットが使えないので、自動的に_に変換される。

# Constants

# Basics

  • scalar と array を値に設定できる。resource は使うな。
  • 変更できない
  • case-sensitive
  • 慣例として名前はすべて大文字にする。 命名規則 => [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*

# Syntax

# 変数との違い

  • $が頭につかない
  • 変数のスコープとは異なり、どこでも宣言でき、どこからでもアクセスできる。
  • 値を変更できない

# 宣言方法

  • constを使う方法とdefine()を使う方法がある。
  • constの場合はコンパイル時に定義されるため、トップレベルのスコープでのみ使用できる。
  • ファンクションやループの中で動的に定義したい場合はdefine()を使うこと。
  • get_defined_constants()で定義済み定数の一覧を Array で取得できる
const CONSTANT = 'Hello World';
define("CONSTANT", "Hello world");

const ANIMALS = array('dog', 'cat', 'bird');
define('ANIMALS', array(
  'dog',
  'cat',
  'bird'
));

# Magic constants

定義済みの定数。コンパイル時に定義される。詳細はこちら (opens new window)

  • __LINE__
  • __FILE__
  • __DIR__
  • __FUNCTION__
  • __CLASS__
  • __TRAIT__
  • __METHOD__
  • __NAMESPACE__
  • ClassName::class

# Expressions

PHP では、すべてが Expressions であり、評価の対象である。

# Expressions とは?

最終的に値になるものすべて。「式」と訳される。

$a = 5
// 5は、integerの5を表すExpressionである
// 代入後は、$aも、int(5)を表すExpressionになる
// さらに、代入後は、'$a = 5'自体も、int(5)を表すExpressionになる

// <= 下記も全部Expression
someFunc()
i++
1 > 5
a += 5

# Statement とは?

何らかのexpression;が Statement である。「文」と訳される。

$b = $a = 5;
// '$b = $a = 5;'がStatement
/// $b, $a, 5, '$a=5' などはExpression

# Operators

# Precedence

  • オペレータの優先順位によって、計算順が決まる
  • 計算順が同じ場合は、Associativity(left or right)により、計算順が決まる。
  • Associativity が non-associative なオペレータを 2 つ以上つなげることはできない

詳細はこちら (opens new window)

# Operators の種類

気になったところだけ記載した。

  • Arithmetic Operators (opens new window)

    • +$a, -$a
  • Assignment Operators (opens new window)

    • $a = 1自体も Expression である
    • combined operators +=, *=など
    • 原則としてすべて値渡しである。object は参照渡しのように見えるが、実際は handle(object の実体への参照のようなもの)を値渡ししている。
    • &newはエラーになる
  • Bitwise Operators (opens new window)

    • 必要になったら調べる
  • Comparison Operators (opens new window)

    • ==,!=,<> タイプの自動変換後の比較

    • ===,!== タイプの自動変換をせずに厳密比較

    • <=> 大きいか(1)、小さいか(-1)、イコールか(0)を返す

      echo 1 <=> 1; // 0
      echo 1 <=> 2; // -1
      echo 2 <=> 1; // 1
      echo "b" <=> "a"; // 1
      
    • Ternary Operator

      $action = (empty($_POST['action'])) ? 'default' : $_POST['action'];
      
    • Null Coalesing(合体) Operator

      • 左辺が null だったときのみ右辺を評価する
      $a = null ?? 'true!';
      

# Error Control Operators

@のこと。Expression に前置すると、その Expression に関するエラーを無視する。 詳細はこちら (opens new window)

# Execution Operators

backtick で囲むことでシェルコマンドを実行できる。

echo `ls -al`;

# Incrementing/Decrementing Operators

++$a, $a++, --$a, $a--

# Logical Operators

  • and どちらも true
  • or 少なくとも 1 つが true
  • xor どちらか一方のみ true
  • !
  • &&
  • ||

and/or= よりも優先度が低い。||/&&=よりも優先度が高い。このため、下記のような事故がおこりがち。

$bool = true && false;
var_dump($bool); // false, that's expected

$bool = true and false;
var_dump($bool); // true, ouch!

# String Operators

.で文字列を接続する。.=も使える。

# Array Operators

  • + 配列を結合する。キー重複時は左辺が優先される。
  • 緩い比較
    • == 同じ key-value ペアを持っているか
    • !=, <> 上記の否定形
  • 厳密な比較
    • === 同じ key-value ペアを持っているかつ、同じ順番、同じタイプか
    • !== 上記の否定形

# Type Operators

  • instanceof あるインスタンスがあるクラスから生成されたかどうかを返す。
  • 継承、インターフェースの実装でも True を返す。
  • 右辺は文字列でも OK
class MyClass{}
class NotMyClass{}
$a = new MyClass;

var_dump($a instanceof MyClass); // true
var_dump($a instanceof NotMyClass); // false

# Control Structures

# JS とほぼ同じ書き方のもの

  • if/elseif/else
  • while
  • do-while
  • for
  • switch

# foreach

配列や Object にループ処理を行う。

foreach (array_expression as $value)
foreach (array_expression as $key => $value)
foreach (array_expression as $key => &$value) // 値を編集したいときは参照渡しにする
  • JS と異なり、下記で言う$colorは foreach の外側でも生きている(マジか)。unset()で削除しておくこと。
$colors = array('red', 'blue', 'green', 'yellow');
foreach ($colors as &$color) {
    $color = strtoupper($color); // 大文字に変換
}
unset($color); // ここでもまだ$colorは生きているのでクリアしておく

# list()

list()では、Array の中身を順番に取り出せる。

list($a, $b, $c) = [1, 2, 3];

これを使うと、ネストした Array の情報をうまく引き出せる

$array = [[1, 2], [3, 4]];
foreach ($array as list($a, $b)) { echo "$a $b" };

# declare

ticks, encoding, strict_typesというものを扱う時に使えるらしい。必要になったらドキュメント (opens new window)を参照する。

# include / require

  • 外部の PHP ファイルを読み込む
  • 読み込みに失敗した時、include は警告するだけだが、require は致命的エラーを投げる
  • includeを記載した場所で利用可能な Variable Scope は、読み込まれた側のファイルですべて利用可能となる。
  • 逆に、読み込まれたファイル内の変数は、includeの場所で宣言されたのと同じように振る舞う。ただし、ファンクションとクラスについては、グローバルとして読み込まれる。

# include_once / require_once

すでに読み込まれていたら読み込まない。

# 別の書き方

  • if,while,for,foreach,switchについては、別の書き方ができる。
  • :ではじめ、endif,endwhile,endfor,endforeach,endswitchで終わる。
<?php if ($expression == true): ?>
  This will show if the expression is true.
<?php else: ?>
  Otherwise this will show.
<?php endif; ?>

# Functions

# User-defined functions

  • すべてのファンクション・クラスはグローバルスコープを持つ。仮に、ファンクション内で宣言したとしても。
  • ファンクションのオーバーロード、再定義はできない
  • ファンクション名は case-insensitive である
  • 宣言した場所よりも前の行でファンクションを呼ぶことができる(一部例外あり)

# Arguments

# 引数の参照渡し

function add_some_extra(&$string)
{
    $string .= 'and something extra.';
}
$str = 'This is a string, ';

# Default Value

function makecoffee($type = "cappuccino"){}

# Type declarations (= 以前は Type hints と呼ばれていた)

function myFunc(string $text) {};

strict モードにすると、自動変換を行わずにエラーを投げるようになる。

declare (strict_types = 1);
function myFunc(string $text)
{
    echo $text;
};
myfunc(123); // => TypeError

TypeError のキャッチ方法

try {
    /* do some error */
} catch (TypeError $e) {
    echo 'Error: '.$e->getMessage();
}

# Variable-length argument list

...を使う。

呼び出される側で展開する

function myFunc(...$args)
{
    var_dump($args);
    // [0]=>  string(5) "hello"
    // [1]=>  string(5) "world"
};
myfunc('hello', 'world');

呼び出し側で展開する

function add($a, $b) {}
echo add(...[1, 2]);

# Returning values

return を省略すると Null が返る。

# array で返す

function small_numbers()
{
    return array (0, 1, 2);
}
list ($zero, $one, $two) = small_numbers();

# 参照を返す

呼び出し側、呼び出され側の両方に&をつける。Reference の項を参照

function &returnsReference()
{
    return $someRef;
}
$newref = &returnsReference();

# Return type declarations

PHP7 からは、返値のタイプを指定できる。strict mode も適用される。

function sum($a, $b): float {}

# Variable functions

string に()をつけると、ファンクションとして実行される。

function foo($text)
{
    echo $text;
}

'foo'('hello'); // hello

$foo = 'foo';
$foo('hello2'); // hello2

インスタンスメソッドにも使える

class Foo
{
    public function Variable()
    {
        $name = 'Bar';
        $this->$name();
    }
    public function Bar()
    {
        echo "This is Bar";
    }
}

$foo = new Foo();
$funcname = "Variable";
$foo->$funcname(); // => This is Bar

# Internal (built-in) functions

使用できる Internal Function は環境により異なる。phpinfo()で読み込まれている Extension を一覧表示することができる。必要に応じて設定を行うこと。

# Anonymous functions

  • Anonymous functions(=closures)
  • コールバック関数として使うときに便利
  • Closure クラスで実装されている
  • 変数に代入できる

# 親スコープの変数を使う方法

  • useを使う。値渡しである。必要があれば&$messageに変えて、参照渡しにすること。
  • useした値は、ファンクションの宣言時の値で固定される。ファンクションを呼んだ時の値ではないので注意する。
$message = 'hello';

$example = function () use ($message) {
    var_dump($message);
};
$example();

# Automatic binding

クラス内の Anonymous Function にある$thisは、自動的にクラスインスタンスにバインドされる。 この挙動がふさわしくない場合は Static anonymous functions を使うこと。

class Test
{
    public function testing()
    {
        $func = function() {
            var_dump($this); // $this はインスタンス自体に自動でバインドされる
        };
        $func();
    }
}

# Static anonymous functions

Static Closure ともいう。クラスインスタンスにバインドされない無名関数。

class Test
{
    public function testing()
    {
        $func = static function () {
            var_dump($this);  // $this はインスタンスにバインドされていない(エラーになる)
        };
        $func();
    }
};

# Classes & Objects

# Basics

  • クラスはプロパティ(Constants, Variables)とメソッド(functions)をもつ。
class SimpleClass
{
    // property declaration
    const CONSTANT = 'some const';
    public $var = 'a default value';

    // method declaration
    public function displayVar() {
        echo $this->var; // $thisはインスタンスを指す
    }
}

# $this

  • $this が何を指すかは、PHP のバージョンや、呼び出し方(静的・非静的)によって異なる。
  • PHP7 の使用は下記の通り。
class A
{
    public function foo()
    {
        if (isset($this)) {
            echo 'defined';
        } else {
            echo "undefined";
        }
    }
}

class B
{
    public function bar()
    {
        A::foo();
    }
}

$a = new A();
$a->foo(); // インスタンスから呼び出した場合は、インスタンス自身を指す
A::foo(); // クラスから静的に呼び出した場合は、undefined

$b = new B();
$b->bar(); // 他のクラスインスタンスから呼び出した場合は、undefined
B::bar(); // 他のクラスから静的に呼び出した場合は、undefined

# new

クラスから新しいインスタンスを作成する。

$instance = new SimpleClass();

クラス内では、new self,new parentとすることで自身を作成できる。

  • Object は、変数内に オブジェクトの実体への参照(handle) を保持している。これは、プリミティブが変数内にデータ自体を保持しているのと比べ、大きく異なる点である。
  • 普通にインスタンスを代入すると、 handle がコピー(値渡し) される。
  • &付きでインスタンスを代入すると、エイリアス(handle を格納している領域への参照を持つ、複数の変数)が作成される。
  • 詳細はこちらのコメント (opens new window)を参照する。
$instance = new SimpleClass();

$assigned = $instance;
$reference = &$instance;

$instance->var = '$assigned will have this value';

$instance = null; // $instance and $reference become null

var_dump($instance); // null
var_dump($reference); // null
var_dump($assigned); // ["var"]=> string(30) "$assigned will have this value"

作成したインスタンスへすぐにアクセスする。

echo (new DateTime())->format('Y');

# プロパティとメソッド

プロパティとメソッドを同じ名前にできる。その場合、呼び出され方によって自動的に選択される。

# extends

  • 他のクラスを 1 つだけ継承できる。
  • メソッドやプロパティは、親でfinalとして定義されていない限りは、子側で上書きできる。
  • parent::で親のメソッド、スタティックプロパティにアクセスできる。

# ::class

Classname::classとすることで、ネームスペースも含めた Fully Qualified Name を取得できる。

namespace NS {
    class ClassName {}

    echo ClassName::class; // => NS\ClassName
}

# Properties

  • プロパティはpublic,protected,privateのいずれかと、名前によって作成される。
  • メソッド内から non-static なプロパティにアクセスするには$this->propertyの記法を使う。
  • メソッド内から static なプロパティにアクセスするには、self::$propertyの記法を使う
  • $thisはクラスインスタンス自体を指す。すべてのクラスメソッドから利用可能。ただし、メソッドが異なるコンテキストから呼ばれた場合は NULL になる。

# Class Constants

  • クラスレベルの定数を設定できる。
  • 定数はスタティックであるので、呼び出しには::を使う。
  • public,protected,privateの 3 つの Visibility がある。
class MyClass
{
    private const PRIVATE_CONST = 'private'; // クラス外からアクセスできない
    public const CONSTANT = 'constant value';

    public function showConstant()
    {
        echo self::CONSTANT;
    }
}

echo MyClass::CONSTANT; // constant value
echo "MyClass"::CONSTANT; // constant value

$class = new MyClass();

$class->showConstant();// constant value
echo $class::CONSTANT; // constant value

# Autoloading Classes

spl_autoload_register()を使うことで、クラス名を元にして必要な外部ファイルを自動で読み込むことができる。

spl_autoload_register(function ($class_name) {
    include $class_name . '.php';
    // => 自動的に、MyClass1.php, MyClass2.php, ITest.phpを読み込む
});

$obj  = new MyClass1();
$obj2 = new MyClass2();
class Foo implements ITest{}

# Constructors and Destructors

# Constructor

  • クラスにはコンストラクタ・デストラクタを設定できる。
  • サブクラスでは親のコンストラクタ・デストラクタは呼ばれないので、必要ならparent::__construct()等で明示的に呼ぶこと
  • 同名のメソッドがコンストラクタとして扱われた時代もあったが、昔のことなので忘れること。
class MyClass
{
    function __construct(){}
    function __destruct(){}
}

# Visibility

  • プロパティ、メソッド、コンスタントのスコープを決めるもの
    • public どこからでも
    • protected そのクラスと、親・子クラスからのみ
    • private そのクラスからのみ

# Property visibility

varで宣言した場合は public になる(非推奨)

# Method Visibility

無印の場合は public になる。

# Constant Visibility

無印の場合は public になる。

# Scope Resolution Operator

::のこと。下記の 3 つの用途で使う。

クラスの外側から、クラス内の定数にアクセスする

echo MyClass::CONST_VALUE;

クラスメソッド内から、クラスのスタティックなメンバにアクセスする

class OtherClass extends MyClass
{
    public static $my_static = 'static var';

    public static function sampleFunc() {
        echo self::$my_static;
    }
}

クラスメソッド内から、親クラスのプロパティ・メソッドにアクセスする

class OtherClass extends MyClass
{
    public static function sampleFunc() {
        echo parent::CONST_VALUE;
        echo parent::sampleFunc();
        echo parent::$my_static;
    }
}

# Static Keyword

  • static に宣言されたクラスのメソッドとプロパティは、クラスのインスタンスを作らなくても使用することができる。
  • static なプロパティには、インスタンスから$instance->$someStaticにようにアクセスできない。$instance::$someStaticならアクセスできる。
  • スタティックメソッドの中では$thisは使えない。インスタンス化していないので当然。

# Class Abstraction

  • Abstract class はインスタンス化できない
  • 部分的に完成されたクラスの雛形
  • Abstract class で宣言されているメソッドは、extends 先でも同じもの(名前、引数のタイプ、等)を実装する必要がある。
abstract class AbstractClass
{
    // force extending class to define these methods
    abstract protected function getValue();
    abstract protected function prefixValue($prefix);
    // common method
    public function printOut(){}
}

class ConcreteClass1 extends AbstractClass
{
    public function getValue(){/* some implementation */}
    public function prefixValue($prefix){/* some implementation */}
}

# Abstract と Interface の違い

// this is saying that "X" agrees to speak language "Y" with your code.
class X implements Y { }

 // this is saying that "X" is going to complete the partial class "Y".
class X extends Y { }

# Object Interfaces

  • インターフェースのメソッドは外部からアクセスするための定義なので、当然すべて public である。
  • extendsを使えば、インターフェースがインターフェースを継承することもできる。
  • ある Object が特定のメソッドを持つことを保証したい時に使う。もっと具体的には、あとで差し替える可能性のあるクラスにインターフェースを実装しておくことで、後の変更を楽にする (opens new window)ためのもの。
interface ITemplate
{
    public function setVariable($name, $var);
    public function getHtml($template);
}

class Template implements ITemplate
{
    public function setVariable($name, $var){}
    public function getHtml($template){}
}

# Traits

  • コードを再利用するための方法。Mixin に近い。
  • 好きな粒度でコードをグループ化できる
  • abstract, static, property, method などを予め作成しておき、クラスにコピペできる。
  • 詳細はドキュメントを参照 (opens new window)
trait SayHello
{
    public function sayHello()
    {
        echo 'Hello ';
    }
}

trait SayWorld
{
    public function sayWorld()
    {
        echo 'World!';
    }
}

class MyHelloWorld
{
    use SayHello, SayWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();

# Anonymous classes

  • サクッと一時的にクラスを作るための機能。PHP7 以降で使用できる。
  • extends, implements, trait, constructor など、通常のクラスと同じことがすべてできる。
  • 詳細 (opens new window)
$util->setLogger(new class {
    public function log($msg)
    {
        echo $msg;
    }
});

# Overloading

  • 動的にプロパティやメソッドを作るための方法。
  • 非常に評判が悪そうなので、必要になったら学習 (opens new window)する。

# Property overloading

__set,__get,__isset,__unset

# Method overloading

__call(),__callStatic()

# Object Iteration

Object のプロパティは Iterable である。

$class = new MyClass();
foreach($class as $key => $value) {}

クラスメソッド内で自身のプロパティを Iterate することもできる。

// この場合、protectedやprivateなプロパティにもアクセスできる
foreach ($this as $key => $value) {}

より細かい制御を行うには、イテレータパターンを使った設定を手動で行う。詳細はドキュメント参照 (opens new window)

# Magic Methods

__で始まるクラスメソッドは、Magic Methods として予約されている。

  • __construct()
  • __destruct()
  • __call()
  • __callStatic()
  • __get()
  • __set()
  • __isset()
  • __unset()
  • __sleep(),__wakeup()
    • serialize, unserialise の前処理
  • __toString()
    • 文字列へのキャスト時の挙動を定義する
  • __invoke()
    • Object 自体を呼び出し可能にする場合に、コードをここに定義する
  • __set_state()
    • var_export()したときの表示内容を定義する?よくわからない
  • __clone()
  • __debugInfo()
    • var_dump()したときの表示内容を定義する

# Final Keyword

親クラスでfinalとして定義したメソッドは、子クラスでオーバーライドできない。 クラスメソッドに対して付与できる。プロパティには付与できない。

class BaseClass {
    final public function moreTesting() {}
}

# Object Cloning

Object をクローンするにはcloneを使う。なお、クラスに__clone()が定義されてる場合は、クローン後の新しい Object においてのみ、__clone()の内容が実行される。

class MyClass{}
$a = new MyClass();
$b = clone $a;

# Comparing Objects

判定条件

  • ==の場合
    • 同じクラスのインスタンスである
    • 同じプロパティを持つ(値は関係ない)
  • ===の場合
    • 全く同じインスタンスである

# Late Static Binding

self::で static なメソッドを呼び出すと、参照先は呼び出し元のクラス内に限定される。 子クラスの static メソッドを参照したい場合は、selfの代わりにstaticを使うこと。

class A
{
    public static function who()
    {
        echo __CLASS__;
    }
    public static function testSelf()
    {
        self::who();
    }
    public static function testStatic()
    {
        static::who();
    }
}

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

B::testSelf(); // => A
B::testStatic(); // => B

# Object Serialization

Object をデシリアライズするときは、そのスコープでクラス定義が参照できないと失敗するので注意。 詳細はこちら (opens new window)

# Namespaces

# Overview

  • ネームスペースの目的は、衝突の回避と、やたら長い名前を短くするため。
  • case-insensitive

# Defining namespaces

ネームスペースの影響を受けるもの

  • classes (including abstracts and traits)
  • interfaces
  • functions
  • constants

namespace の定義はファイルのトップで行う(例外は define だけ)。

<?php
namespace MyProject;
// or
namespace MyProject\Sub\Level; // sub-namespacesも定義できる

napespace ごとにファイルを分けることが望ましい。

# Using namespaces

相対参照

// 現在のネームスペースが\fooなら、下記の参照先は\foo\othernamespaceになる

othernamespace\foo() // ファンクション
othernamespace\foo::staticmethod() // クラスのスタティックメソッド
echo othernamespace\FOO // 定数

絶対参照

\othernamespace\foo(); // 頭に`\`をつける

# namespace operator

自身のネームスペースを指す。相対参照で事足りる気がするので、使いみちがよくわからない。

namespace myspace {
    namespace\mysubspace\hello();
}

namespace myspace\mysubspace {
    function hello()
    {
        echo 'hello!!!!!!!!!!';
    }
}

# __NAMESPACE__

現在のネームスペースを取得する

echo __NAMESPACE__;

# Aliasing/Importing

useを使うことで、下記に対して、エイリアスの作成、インポートができる。

  • class name
  • interface name
  • namespace name
  • function
  • constant
namespace foo;

// importing Class
use My\Full\NSname;
use My\Full\NSname as Another;

// importing a global class
use ArrayObject;

// importing a function (PHP 5.6+)
use function My\Full\functionName;
use function My\Full\functionName as func;

// importing a constant (PHP 5.6+)
use const My\Full\CONSTANT;
  • useでは、ネームスペースは必ず完全修飾であるものとして扱われるので、先頭の\はつけないことが推奨されている。
  • useはコンパイル時に処理されるので、グローバルスコープでしか宣言できない。(ファンクション内では宣言不可)

# グルーピング(PHP7 以降)

use some\namespace\{ClassA, ClassB, ClassC as C};
use function some\namespace\{fn_a, fn_b, fn_c};
use const some\namespace\{ConstA, ConstB, ConstC};

# Fallback to global function/constant

namespace を使用している時、ファンクションと定数はグローバルにフォールバックされるが、クラスはフォールバックされないので注意する。

namespace A\B\C;
new ArrayObject(); // => エラー。`\ArrayObject()`にすればOK。

# Errors

  • エラーにはタイプ (opens new window)がある
  • php.inierror_reporting(もしくはランタイム時ならばerror_reporting())で、エラーの報告レベルを設定できる。報告レベルは、開発環境、本番環境ともにE_ALLにセットしとくのがおすすめ
  • php.inidisplay_errorsで表示有無を設定できる。本番環境ではセキュリティの観点から無効にすること。
  • php.inilog_errorsでログの書き出し有無を設定できる。

# PHP7 でのエラー

  • PHP7 のエラーはErrorクラスになったため、従来のエラー処理方法とはメカニズムが異なっている。Error クラス の特徴は以下の通り

    1. catchブロックにキャッチされるまでバブルアップする。
    2. catch ブロックがなければ、set_exception_hander()でセットされたハンドラが呼ばれる
    3. ハンドラもなければ、エラーは致命的エラーに変換され、従来と同じ方法で処理される
  • Error クラスと Exception クラスは、どちらもThrowableクラスを継承しているので、Throwable で両方キャッチできる。

    try {}catch(Throwable $e) {}
    

# Exceptions

  • 例外のこと
  • throw でき、catch できる。
  • try-catch-finally と組み合わせて使う。
try {
    throw new Exception('Division by zero.');
} catch (Throwable $e) {
    echo 'Caught exception: ', $e->getMessage(), "\n";
}

# Generators

# Overview

  • Generator は簡単に Iterable な Object を作る方法。
  • 通常のファンクションと似ているが、処理途中の状態で値を取り出す(yield)ことができること、その状態を保持したまま何度も呼び出して処理を継続できる点が異なる

たとえば range を generator で実装すると下記のようになる

function xrange($start, $end)
{
    for ($i = $start; $i <= $end; $i += 1) {
        yield $i;
    }
}
foreach (xrange(1, 9) as $number) {
    echo $number;
}
// => 123456789

# Generator Object

generator ファンクションが実行されると、Generatorクラスが返される。 このクラスはIteratorインターフェース (opens new window)を実装している。 これにより、繰り返しの処理を行うことができるようになっている。

# Reference での yield

function &gen_reference() {
    $value = 3;

    while ($value > 0) {
        yield $value;
    }
}
foreach (gen_reference() as &$number) {
    echo --$number;
}
// => 2 1 0

# yield from

yield fromを使うと、generator の中で、別の Traversable(generator, traversable object, array)を返すことができる。

function countToTen()
{
    yield 1;
    yield 2;
    yield from [3, 4];
    yield from new ArrayIterator([5, 6]);
    yield from sevenEight();
    yield 9;
    yield 10;
}
function sevenEight()
{
    yield 7;
    yield from eight();
}
function eight()
{
    yield 8;
}
foreach (countToTen() as $num) {
    echo "$num ";
}
// => 1 2 3 4 5 6 7 8 9 10

# Iterator との比較

Iterator interface を実装したクラスを使う「イテレータパターン」と、Generator を使う場合の違い

  • Iterator の方は、rewind,validなどいろいろと実装しないといけない。一方 Generator はシンプル。
  • ただし、Generator は、一度スタートすると巻き戻しができない、また、繰り返し使用することはできない、などのデメリットも有る。

# Reference

# What is Reference

  • 参照とは、同じ変数に違う名前でアクセスすること。(同じ人が 2 つの名前を持っているようなもの)
  • PHP では変数名とそのコンテンツは別物なので、同じコンテンツで別の名前を持つことができる

# What References Do

# 1. Assign by reference

  • PHP の変数は、向き先(Reference)と、向き先が持つ内容(Content)から成り立つ。
    • 向き先を書き換える方法 $a = &$b
    • コンテンツを書き換える方法 $a = 1

例えば下記では、a とb が同じコンテンツを指すようになる。 a => コンテンツ、b => コンテンツであり、a=>a =>b ではないので注意。

$a = &$b;

同じ記法は、3 番の参照を返すファンクションの結果を受け取る時にも使う。

$foo = &find_var();

# 2. Pass by reference

引数に&をつけると、値として受け取るのではなく、向き先(Reference)として受け取る事ができる。 下記の$valueは、$aのエイリアスである。

function add(&$value)
{
    $value++; // コンテンツをいじる
}

$a=5;
add($a); // => 6

# 3. Return by reference

ファンクション名に&をつけることで、参照を返すファンクションを作成できる。 return したものが自動的に Reference として return される。

function &test()
{
    $val = 1;
    return $val;
}

# What References Are Not

Reference はポインタではない。このため、下記のコードは予想したように動かない。

$origin = '';
$update = 'update!';

function foo(&$arg)
{
    $arg = &$GLOBALS['update'];
    // 書き換わるのは$argの向き先だけ。
    // $argは$originとは別なので、別々の向き先を持てる。
}
foo($origin);
var_dump($origin);
// => ''

# Predefined Variables

  • Superglobals — Superglobals are built-in variables that are always available in all scopes
  • $GLOBALS — References all variables available in global scope
  • $_SERVER — Server and execution environment information
  • $_GET — HTTP GET variables
  • $_POST — HTTP POST variables
  • $_FILES — HTTP File Upload variables
  • $_REQUEST — HTTP Request variables
  • $_SESSION — Session variables
  • $_ENV — Environment variables
  • $_COOKIE — HTTP Cookies
  • $php_errormsg — The previous error message
  • $HTTP_RAW_POST_DATA — Raw POST data
  • $http_response_header — HTTP response headers
  • $argc — The number of arguments passed to script
  • $argv — Array of arguments passed to script

# Predefined Exceptions

  • Exception
  • ErrorException
  • Error
  • ArgumentCountError
  • ArithmeticError
  • AssertionError
  • DivisionByZeroError
  • CompileError
  • ParseError
  • TypeError

# Predefined Interfaces & Classes

  • Traversable
  • Iterator
  • IteratorAggregate
  • Throwable
  • ArrayAccess
  • Serializable
  • Closure
  • Generator

# Context options and parameters

  • Socket context options — Socket context option listing
  • HTTP context options — HTTP context option listing
  • FTP context options — FTP context option listing
  • SSL context options — SSL context option listing
  • CURL context options — CURL context option listing
  • Phar context options — Phar context option listing
  • MongoDB context options — MongoDB context option listing
  • Context parameters — Context parameter listing
  • Zip context options — Zip context option listing

# Tips

# compact

$arr = [
  'apple' => $apple,
  'orange' => $orange,
  'lemon' => $lemon,
];
// 上記は下記と等価
$arr = compact('apple', 'orange', 'lemon');