PHP8.0がリリースされたので新機能全部やる

[PHP8.1](https://qiita.com/rana_kualu/items/e350b8ff80f929626eb9) / [PHP8.0](https://qiita.com/rana_kualu/items/c110cb244c3ee38c6859) / [PHP7.4](https://qiita.com/rana_kualu/items/50f9f5735321fe995ff5)

2020/11/26にPHP8.0.0が[リリースされました](https://www.php.net/releases/8.0/en.php)。

ということで、[UPGRADING](https://github.com/php/php-src/blob/php-8.0.0/UPGRADING)に載っている機能や変更点をだいたい全部見て回ることにします。


# Backward Incompatible Changes

後方互換性のない変更。
なお、ここで削除される機能の多くは[何年も前から公知されています](https://qiita.com/rana_kualu/items/db1ce401df627c46544a)。

## PHPコア

###  `match` is now a reserved keyword.

`match`が予約語になりました。
match構文の導入に伴う措置です。

```php
function match(){}

// PHP8.0
Parse error: syntax error, unexpected token "match", expecting "("
// PHP7.4
エラーは起こらない
```

### Assertion failures now throw by default.

[assert](https://www.php.net/manual/ja/function.assert.php)のデフォルト動作が例外になりました。

```php
assert(false);

// PHP8.0
Fatal error: Uncaught AssertionError: assert(false)
// PHP7.4
Warning: assert(): assert(false) failed
```

PHP7.4以前と同じ動作に戻すにはini設定`assert.exception=0`を設定します。

ちなみにPHP7.0以降、アサート文はコンパイル時に除去されて実行コストが0になるので、気軽に突っ込んでおけます。
便利なのでどんどん使いましょう。

### Removed ability to call non-static methods statically.

静的でないメソッドを静的に呼び出すことができなくなりました。

```php
class HOGE{
    public function fuga(){}
}
HOGE::fuga();

// PHP8.0
Fatal error: Uncaught Error: Non-static method HOGE::fuga() cannot be called statically
// PHP7.4
Deprecated: Non-static method HOGE::fuga() should not be called statically
```

これまでは警告は出るものの実行自体はできていました。
今後は致命的エラーになります。

### Removed (unset) cast.

`(unset)`キャストが削除されました。

```php
$a = 1;
(unset)$a;

// PHP8.0
Fatal error: The (unset) cast is no longer supported
// PHP7.4
Deprecated: The (unset) cast is deprecated
```

今後は普通に`unset($a);`としましょう。

### Removed track_errors ini directive.

ini設定`track_errors`が削除されました。

これは何かというと[$php_errormsg](https://www.php.net/manual/ja/reserved.variables.phperrormsg.php)です。
`track_errors`が有効になっていると、最後に発生したエラーメッセージが`$php_errormsg`に登録されるという謎機能です。
デフォルトはずっとオフで、またPHP7.2でE_DEPRECATEDになったので使っている人もほとんどいないでしょうが、今後は[error_get_last](https://www.php.net/manual/ja/function.error-get-last.php)を使いましょう。

### Removed the ability to define case-insensitive constants.

[define](https://www.php.net/manual/ja/function.define)の第三引数`$case_insensitive`が削除されました。

```php
define('HOGE', 'FUGA', true);
var_dump(HOGE, HoGe);

// PHP8.0
Warning: define(): Argument #3 ($case_insensitive) is ignored
// PHP7.4
FUGA, FUGA // Deprecated: define(): Declaration of case-insensitive constants is deprecated
```

trueにすると定数が大文字小文字を区別しなくなるという意味のわからない機能です。

PHPは大文字小文字を区別するかしないかは[わりかしややこしい](https://qiita.com/tadsan/items/6c6329eeb43929271119)のですが、関数/メソッドは区別しない、それ以外は区別する、という認識でだいたい大丈夫です。
実装上は、一律して区別するものだと考えておいたほうが楽でしょう。

### Access to undefined constants now always results in an Error exception.

未定義定数にアクセスすると致命的エラーが発生します。

```php
var_dump(HOGE);

// PHP8.0
Fatal error: Uncaught Error: Undefined constant "HOGE"
// PHP7.4
HOGE // Warning: Use of undefined constant HOGE - assumed 'HOGE'
```

これまではE_WARNINGを出したうえで、定数名と同じ文字列が割り当てられていましたが、この手抜きができなくなります。

### Removed ability to specify an autoloader using an __autoload() function.

[__autoload](https://www.php.net/manual/ja/function.autoload)関数が削除されました。

```php
function __autoload($class){}

// PHP8.0
Fatal error: __autoload() is no longer supported, use spl_autoload_register() instead
// PHP7.4
Deprecated: __autoload() is deprecated, use spl_autoload_register() instead
```

削除されたといっても完全に消えたわけではなく、定義することもできないという特別扱いです。

今後は[spl_autoload_register](https://www.php.net/manual/ja/function.spl-autoload-register.php)を使いましょう。
Composerのオートロードとか使った方がもっといいですが。

### Removed the $errcontext argument for custom error handlers.

[set_error_handler](https://www.php.net/manual/ja/function.set-error-handler.php)の第1引数`$error_handler`の第5引数`$errcontext`が削除されました。

```php
set_error_handler(function($errno, $errstr, $errfile, $errline, $errcontext){
    echo $errcontext['fuga'];
});

function hoge(){
    $fuga = 'piyo';
    $y = '1a' + 1;
}
hoge();

// PHP8.0
Fatal error: Uncaught ArgumentCountError: Too few arguments to function {closure}(), 4 passed and exactly 5 expected
// PHP7.4
"piyo"
```

エラーが発生した個所のローカル変数が配列で入ってくるという謎機能です。

### Removed create_function().

PHPの魔関数のひとつ[create_function](https://www.php.net/manual/ja/function.create-function.php)が削除されました。

```php
$a = create_function('$a', 'echo $a;');
$a('hoge');

// PHP8.0
Fatal error: Uncaught Error: Call to undefined function create_function
// PHP7.4
"hoge" // Deprecated: Function create_function() is deprecated
```

かわりに[無名関数](https://www.php.net/manual/ja/functions.anonymous.php)を使いましょう。
無名関数はPHP5.3から使えるので、古のソースを熟成させながら使い続けてでもいないかぎり、いまどきcreate_functionはそうそう出てこないはずです。

### Removed each()

[each](https://www.php.net/manual/ja/function.each.php)が削除されました。

```php
$arr = [1, 2, 3];
while ([$key, $val] = each($arr)) {
    var_dump($key, $val);
}

// PHP8.0
Fatal error: Uncaught Error: Call to undefined function each()
// PHP7.4
0,1 1,2 2,3 // Deprecated: The each() function is deprecated
```

この関数を使う意味は全くないので、普通に[foreach](https://www.php.net/manual/ja/control-structures.foreach.php)を[使いましょう](https://qiita.com/rana_kualu/items/0abd2b6f69527b0b4b92)。

### Removed ability to unbind $this from closures

クロージャ内で`$this`のバインドを外すことができなくなりました。
とあるのだけどよくわかりません。

```php
$closure = Closure::bind(null, new stdClass());

// PHP8.0
Fatal error: Uncaught TypeError: Closure::bind(): Argument #1 ($closure) must be of type Closure, null given
// PHP7.4
Warning: Closure::bind() expects parameter 1 to be Closure, null given
```

これは何の意味があるんだ？

### Removed ability to use array_key_exists() with objects

オブジェクトに対して[array_key_exists](https://www.php.net/manual/ja/function.array-key-exists.php)を使えなくなりました。

```php
array_key_exists(1, (object)[0, 1]);

// PHP8.0
Fatal error: Uncaught TypeError: array_key_exists(): Argument #2 ($array) must be of type array, stdClass given
// PHP7.4
Deprecated: array_key_exists(): Using array_key_exists() on objects is deprecated
```

[property_exists](https://www.php.net/manual/ja/function.property-exists.php)を使えってずっと前から言われていたので、今さらこれに引っかかることはないでしょう。

### Made the behavior of array_key_exists() regarding the type of the key parameter consistent with isset() and normal array access.

[array_key_exists](https://www.php.net/manual/ja/function.array-key-exists.php)の引数のキー値の挙動が、[isset](https://www.php.net/manual/ja/function.isset.php)などと同じになりました。

```php
array_key_exists([], [1]);

// PHP8.0
Fatal error: Uncaught TypeError: Illegal offset type
// PHP7.4
Warning: array_key_exists(): The first argument should be either a string or an integer

isset([], [1]); // こちらは昔からFatal error
```

これまでは引数のキー値に配列やオブジェクトなど不正な値を突っ込むことができましたが(当然falseなので意味はない)、今後は`isset`などと同様のチェックが入ります。


### negative_array_index

配列の自動採番キーがマイナスに対応します。

```php
$a = [-10=>1];
$a[] = 2;

// PHP8.0
$a[-9]=>2になる
// PHP7.4
$a[0]=>2になる
```

これは正直、どうして[賛成多数](https://qiita.com/rana_kualu/items/3f47ed79f18aa6427010)なのかわからない。


### The default error_reporting level is now E_ALL.

ini設定[error_reporting](https://www.php.net/manual/ja/errorfunc.configuration.php#ini.error-reporting)のデフォルトがE_ALLになります。
これまではE_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATEDでした。

この変更により、適当に書いてるコードは動かなくなります。

```php
echo $a;

// PHP8.0
Warning: Undefined variable $a
// PHP7.4
何も出ない
```

PHP7.4で何も出ないのは単にデフォルトが非表示になっているだけなので、E_ALLに設定変更すればエラーが出ます。

もちろん`error_reporting`を変更すれば黙殺することもできますが、やめましょう。

### display_startup_errors is now enabled by default.

ini設定[display_startup_errors](https://www.php.net/manual/ja/errorfunc.configuration.php#ini.display-startup-errors)の初期値がオンになりました。


### Using "parent" inside a class that has no parent will now result in a fatal compile-time error.

親クラスの無いクラスで`parent`を書くとコンパイルエラーになります。

```php
class A{
  public function __construct(){
    parent::__construct();
  }
}

// PHP8.0
Fatal error: Cannot use "parent" when current class scope has no parent
// PHP7.4
Deprecated: Cannot use "parent" when current class scope has no parent
```

PHP7.4では、呼ばれないかぎりは警告にとどまります。
もちろん`new A()`を実行したら、parentが存在しないため致命的エラーになります。

### The @ operator will no longer silence fatal errors

[エラー制御演算子@](https://www.php.net/manual/ja/language.operators.errorcontrol.php)が致命的エラーには効かなくなりました。

```php
@require("notfound.php");

// PHP8.0
Fatal error: Uncaught Error: Failed opening required 'notfound.php'
Process exited with code 255.
// PHP7.4
Process exited with code 255.
```

もっとも致命的エラーが起きたらスクリプトは強制終了されるので、結果は特に変わりません。

### Following the hash comment operator # immediately with an opening bracket is not supported as a comment

`#[`はコメントにならなくなりました。

```php
#[ これはコメント

// PHP8.0
Parse error: Unclosed '[' 
// PHP7.4
エラーは起きない
```

[アトリビュート](https://qiita.com/rana_kualu/items/749c389a275f207a8e58)の実装に伴う変更です。
`[`以外の文字はこれまでどおりコメントです。
空白を入れた`# [`もコメントになります。


### LSP violations will now always generate a fatal error

LSP違反となる継承は常に致命的エラーを発生します。

```php
class C1 {
    public function method(array $a) {}
}
class C2 extends C1 {
    public function method(int $a) {}
}

// PHP8.0
Fatal error: Declaration of C2::method(int $a) must be compatible with C1::method(array $a)
// PHP7.4
Warning: Declaration of C2::method(int $a) should be compatible with C1::method(array $a)
```

これまでは場合によってE_FATALだったりE_WARNINGだったりしていたので、これを揃えたものです。


### The precedence of the concatenation operator has changed

連結演算子の[優先度が変更](https://qiita.com/rana_kualu/items/db7ae541016bd0b02122)されます。

```php
$errors_count = 0;
echo 'unknown_upgrade_error_' . $errors_count + 1;

// PHP8.0
unknown_upgrade_error_1
// PHP7.4
1
```

これまで`.`と`+`の優先順位が同じで前から順だったため、直感的ではない結果になることがありました。
今後は`.`の優先順位が下がります。

### Arguments with a default value that resolves to null at runtime will no longer implicitly mark the argument type as nullable

引数のデフォルト値にnullが指定されている場合、引数の型は暗黙的にnull許容型になります。

```php
function test(int $arg = null){}
test(null);
```

型引数は`int`ですが、デフォルト値にnullが指定されているので暗黙的に`?int`型となります。
このようにnullを直接渡した場合の挙動はPHP8でも変わりません。

しかし、デフォルト値を定数などで間接的に渡した場合は暗黙のnull許容型が許されなくなります。

```php
const CONST_RESOLVING_TO_NULL = null;
function test(int $arg = CONST_RESOLVING_TO_NULL){}
test(null);

// PHP8.0
Fatal error: Uncaught TypeError: test(): Argument #1 ($arg) must be of type int, null given
// PHP7.4
エラーは出ない
```

一件ややこしいですが、まあnull許容型の意味を考えれば妥当な変更かなと。


### A number of warnings have been converted into Error exceptions

多くのE_NOTICEがE_WARNINGに、多くのE_WARNINGが例外にと、[警告レベルが厳しくなります](https://qiita.com/rana_kualu/items/2d71a88aab59b35cdcb8)。

```php
$a = new stdClass();
$a->b;

// PHP8.0
Warning: Undefined property: stdClass::$b
// PHP7.4
Notice: Undefined property: stdClass::$b


$a = 1;
$a->b++;

// PHP8.0
Fatal error: Uncaught Error: Attempt to increment/decrement property "b"
// PHP7.4
Warning: Attempt to increment/decrement property 'b' of non-object
```

横着せずに正しいコードを書くようにしましょう。


### Attempting to assign multiple bytes to a string offset will now emit a warning

マルチバイト文字列にオフセットアクセスするとE_WARNINGが出るようになります。

```php
<?php
$str = 'あいうえお';
$str[2] = 'か';

// PHP8.0
Warning: Only the first byte will be assigned to the string offset
// PHP7.4
何も出ない
```

なんにしろ結果は文字化けするので、このようなコードを書いている時点でおそらくバグでしょう。


### Unexpected characters in source files will now result in a ParseError

ヌルバイトなど、ソースコード中に想定外の文字コードが入っているとパースエラーになります。
これまではE_COMPILE_WARNINGでした。


### Uncaught exceptions now go through "clean shutdown"

"destructors will be called after an uncaught exception"、すなわちキャッチされない例外が発生してもデストラクタが呼ばれるようになる、と読めるのですが、でも実際は前から呼ばれてるんですよね。
なんのことかよくわかりません。

```php
class HOGE{
    public function fuga(){
        throw new \Exception();
    }
    
    public function __destruct(){
        echo 'destruct called.';
    }
}
(new HOGE())->fuga();

// PHP8も7.4も
destruct called.
Fatal error: Uncaught Exception
```

### Compile time fatal error "Only variables can be passed by reference" has been delayed until runtime

参照渡し引数に値を渡した際の警告タイミングが変更になりました。

```php
try{
  array_pop([1,2,3]);
}catch(\Throwable $e){
  echo $e->getMessage();
}

// PHP8.0
array_pop(): Argument #1 ($array) cannot be passed by reference
// PHP7.4
Fatal error: Only variables can be passed by reference
```

PHP7.4まではコンパイル時にエラーが出ていたので、プログラム側で制御することができませんでした。
PHP8では評価が実行時まで遅延されるので、結果としてcatchで受け取ることができるようになります。
まあソースコードを修正すべき内容なので、catchできても特に意味はなさそうですが。

### Some "Only variables should be passed by reference" notices have been converted to "Argument cannot be passed by reference" exception.

一部の参照渡し引数に値を渡した時の挙動がE_NOTICEから例外になりました。
とあるのですが実例を見つけられませんでした。

```php
array_pop([1,2,3]); // Fatal error
array_pop(array_values([1,2,3])); // Notice: Only variables should be passed by reference
```

PHP7のころから、値を直接渡した場合はFatal errorとなり、別の関数の返り値をそのまま渡すとE_NOTICEになります。

### The generated name for anonymous classes has changed

匿名クラスの名前が変更になりました。

```php
var_dump(new class extends stdClass{});

// PHP8.0
object(stdClass@anonymous)
// PHP7.4
object(class@anonymous)
```

名前に親クラスやインターフェイスの名前が付くようになり、わかりやすくなります。
しかし、これのせいで互換性が失われる実装って想像もつきませんな。

### Non-absolute trait method references in trait alias adaptations are now required to be unambiguous

トレイトに同じ名前がある場合、曖昧さを消さなければならなくなりました。

```php
trait T1{
    public function foo(){}
}
trait T2{
    public function foo(){}
}

class X{
    use T1, T2{
        foo AS bar;
    }
    public function foo(){}
}

// PHP8.0
Fatal error: An alias was defined for method foo(), which exists in both T1 and T2
// PHP7.4
何もエラー出ない
```

`X::foo()`はどれを指すのかが曖昧ですが、PHP7.4では暗黙的に`T1::foo()`とみなされていました。
PHP8.0では以下のように明示しなければなりません。

```php
class X{
    use T1, T2{
        T1::foo AS bar;
    }
}
```

### The signature of abstract methods defined in traits is now checked against the implementing class method

traitに書いた抽象メソッドを実装したときにシグネチャを正しく解析するようになりました。

```php
trait MyTrait {
  abstract public function neededByTrait(): string;
}

class MyClass {
  use MyTrait;
  public function neededByTrait(): int { return 42; }
}

// PHP8.0
Fatal error: Declaration of MyClass::neededByTrait() must be compatible with MyTrait::neededByTrait()
// PHP7.4
何もエラー出ない
```

今まで異なるシグネチャで実装できていたのがバグなのではという気がしないでもない。

### Disabled functions are now treated exactly like non-existent functions

無効化した関数が存在しない関数と同じ扱いになりました。

具体的には、`php.ini`に`disable_functions ="exec"`と設定したときの結果が異なります。

```php
exec('ls');

// PHP8.0
Fatal error: Uncaught Error: Call to undefined function exec()
// PHP7.4
PHP Warning:  exec() has been disabled for security reasons
```

PHP7.4までの`disable_functions`は、『存在はしているけど無効化されている』という扱いでした。
PHP8においては単純に『存在しない』となるので、別の定義を行うことも可能です。

### data: stream wrappers are no longer writable

[dataストリームラッパー](https://www.php.net/manual/ja/wrappers.data.php)に書き込みできなくなりました。


### The arithmetic and bitwise operators will now consistently throw a TypeError

各種演算子が、引数に配列、リソース、オブジェクトが渡された場合にTypeErrorを出すようになりました。
対象の演算子は`+`・`-`・`*`・`/`・`**`・`%`・`<<`・`>>`・`&`・`|`・`^`・`~`・`++`・`--`です。

```php
new stdClass() + 1;

// PHP8.0
Fatal error:  Uncaught TypeError: Unsupported operand types: stdClass + int
// PHP7.4
Notice:  Object of class stdClass could not be converted to number
```

オブジェクトの場合、GMPのように演算子オーバーロードが設定されている一部のクラスはこれまでどおり計算可能です。

### Float to string casting will now always behave locale-independently

浮動小数から文字列へのキャストがロケールに依存しなくなりました。

```php
setlocale(LC_ALL, 'fr-FR');
echo (string)3.14;

// PHP8.0
3.14
// PHP7.4
3,14
```

フランス語は小数点が','なので、これまでは`3,14`になっていました。
しかし`(float)"3,14"`は解釈できず元に戻せなかったりと、わりと中途半端な機能だったので、ロケールに関わらず常に`3.14`にするようになりました。

### Removed support for deprecated curly braces for offset access

中括弧による文字列オフセットアクセスが削除されました。

```php
echo '12345'{3};

// PHP8.0
Fatal error:  Array and string offset access syntax with curly braces is no longer supported
// PHP7.4
4 Deprecated:  Array and string offset access syntax with curly braces is deprecated
```

何のために存在したのか[よくわからない](https://qiita.com/rana_kualu/items/6ac293f238c4e6000720)機能です。

### Applying the final modifier on a private method will now produce a warning unless that method is the constructor

コンストラクタ以外のprivateメソッドにfinalを書けなくなりました。

```php
class FOO
{
  final private function bar(){}
}

// PHP8.0
Warning:  Private methods cannot be final as they are never overridden by other classes
// PHP7.4
何も出ない
```

privateメソッドはオーバーライドされることはないよ、というE_WARNINGが出ます。
警告なので動作自体はするのですが、今後動かなくなる可能性もありますし、使わない方がよいでしょう。

### If an object constructor exit()s, the object destructor will no longer be called

コンストラクタで`exit()`した場合、デストラクタが呼ばれなくなりました。

```php
class FOO
{
    public function __construct()
    {
        exit();
    }

    public function __destruct()
    {
        echo 'destruct called.';
    }
}
new FOO();

// PHP8.0
何も出ない
// PHP7.4
destruct called.
```

元々コンストラクタで`throw`したときはデストラクタが呼ばれていなかったのですが、それと動作を合わせたということらしいです。


### Non-strict comparisons between numbers and non-numeric strings now work by casting the number to string and comparing the strings

厳密でない比較演算子の数値比較の挙動が変更になりました。
[詳しくはここに書いてあります](https://qiita.com/rana_kualu/items/82cc8295d2102d14b88a)。

```php
var_dump('foo' == 0);

// PHP8.0
false
// PHP7.4
true
```

厳密な比較演算子の挙動は変更ありません。
`===`を使っている限りは安泰です。

### Namespaced names can no longer contain whitespace

名前空間に空白を入れることができなくなりました。

```php
namespace A \ B{}

// PHP8.0
Parse error:  syntax error, unexpected token "\"
// PHP7.4
エラー出ない
```

まあ、今までできていたのがおかしいといえばおかしいのですが。

### Nested ternaries now require explicit parentheses

[曖昧な三項演算子のネストに括弧が必要](https://qiita.com/rana_kualu/items/0de1e406f72c0ef86432)になりました。

```php
1 ? 2 : 3 ?: 4;

// PHP8.0
Fatal error:  Unparenthesized `a ? b : c ?: d` is not supported
// PHP7.4
Deprecated:  Unparenthesized `a ? b : c ?: d` is deprecated
```

PHPの三項演算子は他の大半の言語と[挙動が異なる](https://qiita.com/suin/items/fb5f21f8d1a75542bd8e)という問題がありましたが、それを合わせるための布石です。


### debug_backtrace() and Exception::getTrace() will no longer provide references to arguments

[debug_backtrace](https://www.php.net/manual/ja/function.debug-backtrace.php)および[Exception::getTrace](https://www.php.net/manual/ja/exception.gettrace)が引数の参照を渡さなくなりました。

```php
function foo(&$bar)
{
    debug_backtrace()[0]['args'][0] = 2;
}

$x = 1;
foo($x);
echo $x;

// PHP8.0
1
// PHP7.4
2
```

これまでスタックトレース経由で引数を書き替えるという邪悪な操作ができていたのですが、今後はできなくなります。

### Numeric string handling has been altered to be more intuitive and less error-prone

[数値型文字列の定義が変更になりました](https://qiita.com/rana_kualu/items/fe7998fbe773544d5d25#saner-numeric-strings)。

```php
function foo(int $int){}
foo('123abc');

// PHP8.0
Fatal error:  Uncaught TypeError: foo(): Argument #1 ($int) must be of type int
// PHP7.4
Notice:  A non well formed numeric value encountered
```

PHP7.4までは数値型文字列の定義が『数値型文字列』と『非正規の数値型文字列』の2種類あってわかりにくかったのですが、今後は単純に『数値型文字列』とそれ以外になります。


### Magic Methods will now have their arguments and return types checked if they have them declared

マジックメソッドがシグネチャをチェックするようになりました。

```php
class FOO{
    public function __get(array $name):int{
        return 1;
    }
}

// PHP8.0
PHP Fatal error:  FOO::__get(): Parameter #1 ($name) must be of type string when declared
// PHP7.4
エラー出ない
```

正しい定義に合わせるか、あるいは単にシグネチャを書かないようにすればよいです。

```php
// PHP8.0でもOK
class FOO{
    public function __get($name){
        return 1;
    }
}
```

### call_user_func_array() array keys will now be interpreted as parameter names, instead of being silently ignored

[call_user_func_array](https://www.php.net/manual/ja/function.call-user-func-array.php)に連想配列を渡したときに、キーが無視されなくなりました。

```php
function foo(...$args){
    var_dump($args);
}
call_user_func_array('foo', ['a'=>1, 'b'=>2]);

// PHP8.0
['a'=>1, 'b'=>2]
// PHP7.4
[1, 2]
```

そもそもcall_user_func_arrayなんか使うなって話だな。

## COM

### Removed the ability to import case-insensitive constants from type libraries

COMのタイプライブラリ定数の大文字小文字を区別しない機能が削除されました。
[com_load_typelib](https://www.php.net/manual/ja/function.com-load-typelib)の第二引数は常にtrueとなり、[com.autoregister_casesensitive](https://www.php.net/manual/ja/com.configuration.php#ini.com.autoregister-casesensitive)も常にonとなります。

ということらしいのだけど、そもそもタイプライブラリって何だ。

## Curl

### CURLOPT_POSTFIELDS no longer accepts objects as arrays

[CURLOPT_POSTFIELDS](https://www.php.net/manual/ja/function.curl-setopt.php)はオブジェクトを受け取らなくなりました。

```php
$c = curl_init();
curl_setopt($c, CURLOPT_POSTFIELDS, (object)['a'=>1]);

// PHP8.0
Fatal error:  Uncaught Error: Object of class stdClass could not be converted to string
// PHP7.4
エラー出ない
```

そもそも最初から文字列か配列しか受け取らないという仕様で、オブジェクトを受け取れていたのはたまたまです。
今後は普通に配列を渡せば問題ありません。

## Date

### mktime() and gmmktime() now require at least one argument

[mktime](https://www.php.net/manual/ja/function.mktime.php)と[gmmktime](https://www.php.net/manual/ja/function.gmmktime)は、最低ひとつの引数が必要になりました。

```php
mktime();

// PHP8.0
Fatal error:  Uncaught ArgumentCountError: mktime() expects at least 1 argument, 0 given
// PHP7.4
Deprecated:  mktime(): You should be using the time()
```

単に現在時刻がほしいときは[time](https://www.php.net/manual/ja/function.time)を使え、ということらしいです。

## DOM

### Remove unimplemented classes from ext/dom that had no behavior and contained test data

定義だけあって実装のなかった、あるいは実験的実装だったDOM関連クラスが削除されました。

```php

new DOMTypeInfo();

// PHP8.0
Fatal error:  Uncaught Error: Class "DOMTypeInfo" not found
// PHP7.4
エラー出ない
```

具体的にはDOMNameList / DomImplementationList / DOMConfiguration / DomError / DomErrorHandler / DOMImplementationSource / DOMLocator / DOMUserDataHandler / DOMTypeInfoが削除されました。
これらは[DOMスタンダード](https://triple-underscore.github.io/DOM4-ja.html)からも削除されているため、それと合わせたものとなります。
[マニュアル](https://www.php.net/manual/ja/book.dom.php)にも元々入ってなかったので影響も極小でしょう。

## Enchant

### enchant_broker_list_dicts(), enchant_broker_describe() and enchant_dict_suggest() will now return an empty array instead of null

[enchant_broker_list_dicts](https://www.php.net/manual/ja/function.enchant-broker-list-dicts.php)等の関数が、対象がなにもないときに`null`ではなく`[]`を返すようになりました。

### enchant_broker_init() will now return an EnchantBroker object rather than a resource

[enchant_broker_init](https://www.php.net/manual/ja/function.enchant-broker-init)は、これまでリソースを返していたのがEnchantBrokerオブジェクトを返すようになりました。

他の[Enchant関数](https://www.php.net/manual/ja/ref.enchant.php)はこれまでと同じ書き方で透過的に動作します。

### enchant_broker_request_dict() and enchant_broker_request_pwl_dict() will now return an EnchantDictionary object rather than a resource

[enchant_broker_request_dict](https://www.php.net/manual/ja/function.enchant-broker-request-dict)と[enchant_broker_request_pwl_dict](https://www.php.net/manual/ja/function.enchant-broker-request-pwl-dict)は、これまでリソースを返していたのがEnchantDictionaryオブジェクトを返すようになりました。

ていうかEnchantって[PHP7.3で削除される](https://qiita.com/rana_kualu/items/2d13ec52279875ea4725#enchant)という話だったんだけどどうなったんだ？

## Exif

### Removed read_exif_data

[read_exif_data](https://www.php.net/manual/ja/function.read-exif-data.php)が削除されました。

今後は[exif_read_data](https://www.php.net/manual/ja/function.exif-read-data.php)を使いましょう。

## Filter

### The FILTER_FLAG_SCHEME_REQUIRED and FILTER_FLAG_HOST_REQUIRED flags for the FILTER_VALIDATE_URL filter have been removed

検証フィルタ[FILTER_VALIDATE_URL](https://www.php.net/manual/ja/filter.filters.validate.php)において、`FILTER_FLAG_SCHEME_REQUIRED`と`FILTER_FLAG_HOST_REQUIRED`のフラグが削除されました。

実はプロトコルスキームとホストは元から常に必須だったため、実質的に意味のないフラグでした。

### The INPUT_REQUEST and INPUT_SESSION source for filter_input() etc have been removed

[filter_input](https://www.php.net/manual/ja/function.filter-input)などのフラグINPUT_REQUESTとINPUT_SESSIONが削除されました。

そもそも[実装されていません](https://qiita.com/sj-i/items/5dae03d6ad66b9f5f3da#nikic-remove-input_session-and-input_request)でした。

## GD

### The GD extension now uses a GdImage objects as the underlying data structure for images, rather than resources

GDリソースがGdImageオブジェクトになりました。

```php
$image = imagecreatetruecolor(100, 100);
$text_color = imagecolorallocate($image, 233, 14, 91);
imagestring($image, 1, 5, 5, 'TEXT', $text_color);
imagepng($image);

echo gettype($image);

// PHP8.0
object
// PHP7.4
resource
```

この変更は透過的です。
上記コードの`$image`はPHP7.4ではリソースであるのに対してPHP8.0ではオブジェクトになりますが、どちらでも同じように動作します。

ただし[is_resource](https://www.php.net/manual/ja/function.is-resource)などでチェックを入れている場合は動かなくなります。

### The deprecated function image2wbmp() has been removed

[image2wbmp](https://www.php.net/manual/ja/function.image2wbmp)関数が削除されました。

PHP7.3以降E_DEPRECATEでした。

### The deprecated functions png2wbmp() and jpeg2wbmp() have been removed

同じく非推奨だった[png2wbmp](https://www.php.net/manual/ja/function.png2wbmp)と[jpeg2wbmp](https://www.php.net/manual/ja/function.jpeg2wbmp)も削除されました。

### The default $mode parameter of imagecropauto() no longer accepts -1.

[imagecropauto](https://www.php.net/manual/ja/function.imagecropauto)の第二引数`$mode`は`-1`を受け付けなくなりました。

```php
$image = imagecreatetruecolor(100, 100);
imagecropauto($image, -1, 0.5);

// PHP8.0
Fatal error:  Uncaught ValueError: imagecropauto(): Argument #2 ($mode) must be a valid mode
// PHP7.4
Deprecated:  imagecropauto(): Crop mode -1 is deprecated
```

IMG_CROP_DEFAULTなどの定数を使いましょう。

## GMP

### gmp_random() has been removed

[gmp_random](https://www.php.net/manual/ja/function.gmp-random)が削除されました。

この関数は[プラットフォームに依存して出力が変わる](https://qiita.com/rana_kualu/items/db1ce401df627c46544a#the-gmp_random-function-has-been-deprecated)という問題があったため、PHP7.2でE_DEPRECATEDになりました。
かわりに[gmp_random_bits](http://php.net/manual/ja/function.gmp-random-bits.php)か[gmp_random_range](https://www.php.net/manual/ja/function.gmp-random-range.php)を使いましょう。

## Iconv

### iconv() implementations which do not properly set errno in case of errors are no longer supported

[iconv](https://www.php.net/manual/ja/function.iconv.php)は、エラー時にerrnoプロパティを適切にセットしない実装はサポートしなくなりました。

と書かれているのですが、errnoがなんなのか一切出てこないので何を見て判断すればよいのかわかりません。

## IMAP

### The unused default_host argument of imap_headerinfo() has been removed

[imap_headerinfo](https://www.php.net/manual/ja/function.imap-headerinfo)の未使用だった第五引数`$defaulthost`が削除されました。

### The imap_header() function which is an alias of imap_headerinfo() has been removed

[imap_header](https://www.php.net/manual/ja/function.imap-header)が削除されました。

imap_headerinfoのエイリアスです。

## Intl

### The deprecated constant INTL_IDNA_VARIANT_2003 has been removed

定数`INTL_IDNA_VARIANT_2003`が削除されました。

これはUnicodeから[削除されたため](https://sourceforge.net/p/icu/mailman/message/32980778/)です。

### The deprecated Normalizer::NONE constant has been removed

[Normalizer::NONE](https://www.php.net/manual/ja/class.normalizer.php)が削除されました。

何もしないという意味のない設定です。

### The IntlDateFormatter::RELATIVE_FULL, RELATIVE_LONG, RELATIVE_MEDIUM, and RELATIVE_SHORT constants have been added.

[IntlDateFormatter](https://www.php.net/manual/ja/class.intldateformatter.php)クラスに定数RELATIVE_FULL/RELATIVE_LONG/RELATIVE_MEDIUM/RELATIVE_SHORTが追加されました。

追加は互換性のない変更ではないような気がする。

## LDAP

### The deprecated function ldap_sort / ldap_control_paged_result / ldap_control_paged_result_response has been removed

関数[ldap_sort](https://www.php.net/manual/ja/function.ldap-sort)、[ldap_control_paged_result](https://www.php.net/manual/ja/function.ldap-control-paged-result)、[ldap_control_paged_result_response](https://www.php.net/manual/ja/function.ldap-control-paged-result-response.php)が削除されました。

かわりに[ldap_search](https://www.php.net/manual/ja/function.ldap-search.php)を使いましょう。

### The interface of ldap_set_rebind_proc has changed

[ldap_set_rebind_proc](https://www.php.net/manual/ja/function.ldap-set-rebind-proc)の第二引数`$callback`が空白""を受け付けなくなりました。

設定を外したい場合はかわりにnullを使います。

## Mbstring

### The mbstring.func_overload directive has been removed

マルチバイト関数の[関数オーバーロード機能](https://www.php.net/manual/ja/mbstring.overload.php)が削除されました。

[substr](https://www.php.net/manual/ja/function.substr.php)を使うと自動的に[mb_substr](https://www.php.net/manual/ja/function.mb-substr.php)が呼ばれる、といった機能なのですが、事故の元でしかありません。

機能の削除に伴い、定数[MB_OVERLOAD_MAIL](https://www.php.net/manual/ja/mbstring.constants.php)、[mb_get_info](https://www.php.net/manual/ja/function.mb-get-info)の`func_overload`といった関連項目も削除されます。

### mb_parse_str() can no longer be used without specifying a result array

[mb_parse_str](https://www.php.net/manual/ja/function.mb-parse-str)の第二引数`$array`が必須になりました。

```php
mb_parse_str('a=b');
echo $a;

// PHP8.0
Fatal error:  Uncaught ArgumentCountError: mb_parse_str() expects exactly 2 arguments, 1 given
// PHP7.4
b // Deprecated:  mb_parse_str(): Calling mb_parse_str() without the result argument is deprecated
```

元々は文字列を直接変数に展開するという危険極まりない関数だったのですが、この変更により配列に展開するという妥当な内容になりました。
`$array = mb_parse_str('a=b')`とできればもっと良かったのですけどね。

###  A number of deprecated mbregex aliases have been removed

いくつかのマルチバイト正規表現関数に存在したエイリアスが削除されました。

```php
mbsplit("//u", 'foo');

// PHP8.0
Fatal error:  Uncaught Error: Call to undefined function mbsplit
// PHP7.4
Deprecated:  Function mbsplit() is deprecated
```

なぜか[mb_ereg](https://www.php.net/manual/ja/function.mb-ereg)や[mb_regex_encoding](https://www.php.net/manual/ja/function.mb-regex-encoding)などには、`mbereg`や`mbregex_encoding`といった`_`のないエイリアスが存在しました。
これらはマニュアルにも全く存在しない、謎のエイリアスです。

### The 'e' modifier for mb_ereg_replace() has been removed

[mb_ereg_replace](https://www.php.net/manual/ja/function.mb-ereg-replace)においてオプション`e`が削除されました。

[preg_replaceでは7.0で削除された](https://qiita.com/rana_kualu/items/572494021917fbb93c95#deprecate-mb_ereg_replace-eval-option)のに何故かこっちには残っていたのですが、ようやく揃った形です。

今後は[mb_ereg_replace_callback](https://www.php.net/manual/ja/function.mb-ereg-replace-callback)を使う必要があります。

### A non-string pattern argument to mb_ereg_replace() will now be interpreted as a string instead of an ASCII codepoint

[mb_ereg_replace](https://www.php.net/manual/ja/function.mb-ereg-replace.php)において、第一引数`$pattern`のASCIIコード変換を行わなくなります。

```php
echo mb_ereg_replace(98, 'x', 'abc98');

// PHP8.0
"abcx"
// PHP7.4
"axc98" // Deprecated:  mb_ereg_replace(): Non-string patterns will be interpreted as strings in the future
```

第一引数に数値を渡した場合、これまでは何故か対応する[ASCIIコード](http://www.asciitable.com/)として扱われていました。
意味もないうえにわかりにくすぎるので、今後は単純に文字列として扱われます。

### The needle argument for mb_strpos(), mb_strrpos(), mb_stripos(), mb_strripos(), mb_strstr(), mb_stristr(), mb_strrchr() and mb_strrichr() can now be empty

[mb_strpos](https://www.php.net/manual/ja/function.mb-strpos)などの各関数において、引数`$needle`に空白が許可されます。

```php
echo mb_strpos('abcde', '');

// PHP8.0
0
// PHP7.4
false // Warning:  mb_strpos(): Empty delimiter
```

""はあらゆる文字列にマッチするため、だいたい1文字目になります。

### The $is_hex parameter, which was not used internally, has been removed from mb_decode_numericentity()

[mb_decode_numericentity](https://www.php.net/manual/ja/function.mb-decode-numericentity)において、使われていなかった引数`$is_hex`が削除されました。

### The legacy behavior of passing the encoding as the third argument instead of an offset for the mb_strrpos() function has been removed

[mb_strrpos](https://www.php.net/manual/ja/function.mb-strrpos)の、引数`$encoding`は第四引数ですが、これを第三引数に書いても動く機能が削除されました。

```php
mb_strrpos('b', 'abc', 'UTF-8');

// PHP8.0
Fatal error:  Uncaught TypeError: mb_strrpos(): Argument #3 ($offset) must be of type int, string given
// PHP7.4
Deprecated:  mb_strrpos(): Passing the encoding as third parameter is deprecated
```

引数の位置が変更されたのはPHP5.2です。
今まで残ってたことにびっくりですね。


### The ISO_8859-* character encoding aliases have been replaced by ISO8859-* aliases

[サポートされる文字エンコーディング](https://www.php.net/manual/ja/mbstring.supported-encodings.php)のうち、`ISO-8859-x`のエイリアスが変更されました。

```php
mb_detect_order(['ISO-8859-1', 'ISO_8859-2']);
var_dump(mb_detect_order());

// PHP8.0
Fatal error:  Uncaught ValueError: mb_detect_order(): Argument #1 ($encoding) contains invalid encoding
// PHP7.4
['ISO-8859-1', 'ISO-8859-2']
```

これまで`ISO_8859-x`という形のエイリアスが存在したのですが、PHP8.0では使えなくなりました。
かわりに`ISO8859-x`というエイリアスが使えるようになりますが、これはPHP7.4では対応していません。

iconvと形を揃えるためだそうですが、いきなり完全に差し替える必要に陥ります。
とはいえ、最初からエイリアスではなく`ISO-8859-x`の正しい形を使っていれば特に問題ありません。

### mb_ereg() and mb_eregi() will now return boolean true on a successful match

[mb_ereg](https://www.php.net/manual/ja/function.mb-ereg)と[mb_eregi](https://www.php.net/manual/ja/function.mb-eregi)が、マッチしたらtrueを返すようになりました。

```php
echo mb_ereg('bbb', 'abbbc', $regs);

// PHP8.0
true
// PHP7.4
3
```

これまでは第三引数`$regs`の有無によって返り値の値も型も変わるという非常に使いにくいものでした。
この変更によって、マッチしたらtrue、しなかったらfalseとわかりやすい形になります。

## OCI8

### The OCI-Lob class is now called OCILob, and the OCI-Collection class is now called OCICollection

[OCI-Lob](https://www.php.net/manual/ja/class.OCI-Lob.php)クラスが`OCILob`に、[OCI-Collection](https://www.php.net/manual/ja/class.OCI-Collection.php)クラスがOCICollectionに変更されました。

### Several alias functions have been marked as deprecated

幾つかの関数のエイリアスが非推奨になりました。

### oci_internal_debug() and its alias ociinternaldebug() have been removed

[oci_internal_debug](https://www.php.net/manual/ja/function.oci-internal-debug)が削除されました。

## ODBC

### odbc_connect() no longer reuses persistent connections

[odbc_connect](https://www.php.net/manual/ja/function.odbc-connect)が持続的接続を利用しなくなりました。

よくわかりませんが、[odbc_pconnect](https://www.php.net/manual/ja/function.odbc-pconnect.php)のほうに`同じ dsn、user、 password の組み合わせ （odbc_connect() および odbc_pconnect() による）接続の場合は、 持続的な接続を再利用する`とか書いてあるので、おそらく一度`odbc_pconnect`したあとに`odbc_connect`したら持続的接続になってしまっていたのではないかと思われます。

### The unused flags parameter of odbc_exec() has been removed

[odbc_exec](https://www.php.net/manual/ja/function.odbc-exec)の第三引数`$flags`は未使用だったため削除されました。

## OpenSSL

### openssl_x509_read() and openssl_csr_sign() will now return an OpenSSLCertificate object rather than a resource

[openssl_x509_read](https://www.php.net/manual/ja/function.openssl-x509-read.php)と[openssl_csr_sign](https://www.php.net/manual/ja/function.openssl-csr-sign.php)は、これまでリソースを返していたのをOpenSSLCertificateオブジェクトを返すようになりました。

### The openssl_x509_free() function is deprecated

[openssl_x509_free](https://www.php.net/manual/ja/function.openssl-x509-free.php)はE_DEPRECATEDとなり、何もしなくなりました。

↑の変更で対象がリソースからオブジェクトになったので、わざわざ関数で開放しなくても自動的に解放されるからです。


### openssl_csr_new() will now return an OpenSSLCertificateSigningRequest object rather than a resource

[openssl_csr_new](https://www.php.net/manual/ja/function.openssl-csr-new)もリソースではなくOpenSSLCertificateSigningRequestオブジェクトを返すようになりました。

### openssl_pkey_new() will now return an OpenSSLAsymmetricKey object rather than a resource

[openssl_pkey_new](https://www.php.net/manual/ja/function.openssl-pkey-new.php)もOpenSSLAsymmetricKeyオブジェクトを以下略


### The openssl_pkey_free() function is deprecated

[openssl_pkey_free](https://www.php.net/manual/ja/function.openssl-pkey-free.php)はE_DEPRECATEDとなり、何もしなくなりました。

### openssl_seal() and openssl_open() now require $method to be passed

[openssl_seal](https://www.php.net/manual/ja/function.openssl-seal.php)と[openssl_open](https://www.php.net/manual/ja/function.openssl-open.php)の引数`$method`が必須になりました。
デフォルト値が`'RC4'`で、これはセキュアではないためです。

## PCRE

### When passing invalid escape sequences they are no longer interpreted as literals

無効なエスケープシーエンスが文字列リテラルと解釈されなくなりました。

```php
preg_match('/\i/', 'h\ij', $matches);
var_dump($matches);

// PHP8.0
null // Warning:  preg_match(): Compilation failed: unrecognized character
// PHP7.4
[0=>"i"]
```

[正規表現パターン](https://www.php.net/manual/ja/regexp.reference.escape.php)に存在しない文字列`\i`は、これまでは単なる文字列と解釈されていましたが、今後は不正なパターンとみなされてエラーが出るようになります。
`\i`という文字列で検索したい場合は、正しく`\\\\i`と記述しましょう。

## PDO

### The default error handling mode has been changed from "silent" to "exceptions"

[PDO](https://www.php.net/manual/ja/book.pdo.php)の[エラーモード](https://www.php.net/manual/ja/pdo.error-handling.php)`PDO::ATTR_ERRMODE`のデフォルト値が`PDO::ERRMODE_EXCEPTION`になりました。
これまでは`PDO::ERRMODE_SILENT`でした。

### The signatures of some PDO methods have changed

幾つかのメソッドにおいてシグネチャが変更されました。
例として[PDOStatement::setFetchMode](https://www.php.net/manual/ja/pdostatement.setfetchmode.php)は、`PDOStatement::setFetchMode(int $mode, ...$params)`になります。

## PDO_ODBC

### The php.ini directive pdo_odbc.db2_instance_name has been removed

[pdo_odbc.db2_instance_name](https://www.php.net/manual/ja/ref.pdo-odbc.php#ini.pdo-odbc.db2-instance-name)ディレクティブが削除されました。

これを設定すると環境変数DB2INSTANCEに値が入るだけというよくわからないディレクティブなので、まあ削除されても妥当でしょう。

## pgsql

### The deprecated pg_connect() syntax using multiple parameters instead of a connection string is no longer supported

[pg_connect](https://www.php.net/manual/ja/function.pg-connect)において、DSNを使わない形の古い構文が削除されました。

```php
pg_connect("host", "port", "options", "tty", "dbname");

// PHP8.0
Fatal error:  Uncaught ArgumentCountError: pg_connect() expects at most 2 arguments, 5 given
// PHP7.4
エラー出ない
```

mysqliもPDOも既にDSN形式以外は対応していないので、こちらもいつまでも残しておく必要はないでしょう。

### The deprecated pg_lo_import() and pg_lo_export() signature that passes the connection as the last argument is no longer supported

[pg_lo_import](https://www.php.net/manual/ja/function.pg-lo-import)および[pg_lo_export](https://www.php.net/manual/ja/function.pg-lo-export.php)は、実は第三引数にリソースを渡しても動いていたらしいのですが、それが削除されました。

そんな構文ドキュメントにもユーザノートにも全く書かれていないのですが、PHP7.4のソースにはたしかにそれっぽいものが書いてあって、PHP8.0ではそれがなくなっていました。
これ使ってる人とかいるんだろうか。

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/9d64786b-979e-18f8-5d3e-ddd1c7a2b171.png)


### pg_fetch_all() will now return an empty array instead of false for result sets with zero rows

[pg_fetch_all](https://www.php.net/manual/ja/function.pg-fetch-all.php)は、取得行数が0だった場合はfalseを返していたのですが、`[]`を返すようになりました。

失敗ではなく結果が無いということなので、こちらが妥当でしょう。

## Phar

### Metadata associated with a phar will no longer be automatically unserialized

これまではPharファイルを読み込もうとした時点で自動的にメタデータが展開されていたのですが、自動的には呼ばれなくなりました。

[セキュリティ上の理由](https://qiita.com/rana_kualu/items/fe7998fbe773544d5d25#dont-automatically-unserialize-phar-metadata-outside-getmetadata)です。

## Reflection

### The method signatures have been changed

幾つかの関数のシグネチャが変更されました。

```php
// PHP7.4
ReflectionClass::newInstance($args)
ReflectionFunction::invoke($args)
ReflectionMethod::invoke($object, $args)

// PHP8.0
ReflectionClass::newInstance(...$args)
ReflectionFunction::invoke(...$args)
ReflectionMethod::invoke($object, ...$args)
```

### The ReflectionType::__toString() method will now return a complete debug representation of the type, and is no longer deprecated

[ReflectionType::__toString](https://www.php.net/manual/ja/reflectiontype.tostring)は非推奨でなくなりました。

```php
function hoge(?int $a){}
echo (new ReflectionFunction('hoge'))->getParameters()[0]->getType();

// PHP8.0
?int
// PHP7.4
int
```

また、これまで正確に取ってこれなかったnullableなども取ってこれるようになっています。

### Reflection export() methods have been removed

[Reflection::export](https://www.php.net/manual/ja/reflection.export.php)は削除されました。

```php
ReflectionFunction::export('strpos');

// PHP8.0
Fatal error:  Uncaught Error: Call to undefined method ReflectionFunction::export()
// PHP7.4
Function [ <internal:standard> function strpos ]
```

ざっくり概要確認するには便利だったんですけどね。

### The following methods can now return information about default values of parameters of internal functions

[ReflectionParameter::isDefaultValueAvailable](https://www.php.net/manual/ja/reflectionparameter.isdefaultvalueavailable.php)、[getDefaultValue](https://www.php.net/manual/ja/reflectionparameter.getdefaultvalue.php)、[isDefaultValueConstant](https://www.php.net/manual/ja/reflectionparameter.isdefaultvalueconstant.php)、[getDefaultValueConstantName](https://www.php.net/manual/ja/reflectionparameter.getdefaultvalueconstantname.php)が内部関数にも使えるようになりました。

```php
(new ReflectionFunction('strpos'))->getParameters()[2]->getDefaultValue();

// PHP8.0
0
// PHP7.4
Fatal error:  Uncaught ReflectionException: Cannot determine default value for internal functions
```

内部関数に対して使う意義はあんまり感じられませんが。

### ReflectionMethod::isConstructor() and ReflectionMethod::isDestructor() now also return true

[ReflectionMethod::isConstructor](https://www.php.net/manual/ja/reflectionmethod.isconstructor.php)および[isDestructor](https://www.php.net/manual/ja/reflectionmethod.isdestructor.php)は、インターフェイスにもtrueを返すようになりました。
これまではインターフェイスには非対応でした。

```php
interface HOGE{
	public function __construct();
}
(new ReflectionMethod('HOGE', '__construct'))->isConstructor();

// PHP8.0
true
// PHP7.4
false
```

ちなみにtraitには昔からtrueを返します。


### ReflectionType::isBuiltin() method has been moved to ReflectionNamedType

[ReflectionType::isBuiltin](https://www.php.net/manual/ja/reflectiontype.isbuiltin.php)は[ReflectionNamedType](https://www.php.net/manual/ja/class.reflectionnamedtype.php)クラスに移動しました。
なぜならReflectionUnionTypeにはビルトインの型はないからです。

## Sockets

### The deprecated AI_IDN_ALLOW_UNASSIGNED and AI_IDN_USE_STD3_ASCII_RULES flags for socket_addrinfo_lookup() have been removed

[socket_addrinfo_lookup](https://www.php.net/manual/ja/function.socket-addrinfo-lookup)関数の第三引数に渡せるフラグAI_IDN_ALLOW_UNASSIGNED/AI_IDN_USE_STD3_ASCII_RULESが削除されました。

glibcで削除されたので追随したということのようです。

### socket_create(), socket_create_listen(), etc will now return a Socket object rather than a resource

以下の各関数が、リソースではなくオブジェクトを返すようになりました。
[socket_create](https://www.php.net/manual/ja/function.socket-create) / [socket_create_listen](https://www.php.net/manual/ja/function.socket-create-listen.php) / [socket_accept](https://www.php.net/manual/ja/function.socket-accept.php) / [socket_import_stream](https://www.php.net/manual/ja/function.socket-import-stream) / [socket_addrinfo_connect](https://www.php.net/manual/ja/function.socket-addrinfo-connect) / [socket_addrinfo_bind](https://www.php.net/manual/ja/function.socket-addrinfo-bind) / [socket_wsaprotocol_info_import](https://www.php.net/manual/ja/function.socket-wsaprotocol-info-import)

```php
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_set_option($socket, IPPROTO_IP, IP_MULTICAST_LOOP, 0);
var_dump($socket);

// PHP8.0
object(Socket)#1 (0) {}
// PHP7.4
resource of type (Socket)
```

[socket_set_option](https://www.php.net/manual/ja/function.socket-set-option)のようなソケットを引数として受け取る関数は、そのまま透過的に動作します。
ただしis_resource等でチェックしている場合は修正が必要です。

### socket_addrinfo_lookup() will now return an array of AddressInfo objects rather than resources

[socket_addrinfo_lookup](https://www.php.net/manual/ja/function.socket-addrinfo-lookup)は、リソースの配列ではなく、AddressInfoの配列を返すようになりました。

## SPL

### SplFileObject::fgetss() has been removed

[SplFileObject::fgetss](https://www.php.net/manual/ja/splfileobject.fgetss.php)は削除されました。

### SplHeap::compare($a, $b) now specifies a method signature

[SplHeap::compare](https://www.php.net/manual/ja/splheap.compare)に型mixedが設定されました。
extendsする場合は型を指定するか、もしくは何も書かないかが必要です。

### SplDoublyLinkedList::push() now returns void instead of true

[SplDoublyLinkedList::push](https://www.php.net/manual/ja/spldoublylinkedlist.push)がvoidを返すようになりました。

```php
var_dump((new SplDoublyLinkedList())->push(1));

// PHP8.0
null
// PHP7.4
true
```

これまではtrueを返していました。
元々マニュアルにもvoidと書かれていて、trueを返すのはバグだったみたいです。

### SplDoublyLinkedList::unshift() now returns void instead of true

[SplDoublyLinkedList::unshift](https://www.php.net/manual/ja/spldoublylinkedlist.unshift)がvoidを以下同文。

### SplQueue::enqueue() now returns void instead of true

[SplQueue::enqueue](https://www.php.net/manual/ja/splqueue.enqueue)が以下同文。

### spl_autoload_register() will now always throw a TypeError on invalid arguments

[spl_autoload_register](https://www.php.net/manual/ja/function.spl-autoload-register)は、無効な引数について常にTypeErrorを発するようになりました。

```php
spl_autoload_register('HOGE', false);

// PHP8.0
Fatal error:  Uncaught TypeError: spl_autoload_register(): Argument #1 ($callback) must be a valid callback, function "HOGE" not found or invalid function name
// PHP7.4
何も出ない
```

これに伴い、第二引数`$throw`は常に無視されるようになります。

### SplFixedArray is now an IteratorAggregate and not an Iterator

[SplFixedArray](https://www.php.net/manual/ja/class.splfixedarray.php)が[IteratorAggregate](https://www.php.net/manual/ja/class.iteratoraggregate.php)をimplementsしました。

```php
var_dump(
	is_subclass_of('SplFixedArray', 'Iterator'),
	is_subclass_of('SplFixedArray', 'IteratorAggregate'),
);

// PHP8.0
false, true
// PHP7.4
true, false
```

これまでは[Iterator](https://www.php.net/manual/ja/class.iterator.php)をimplementsしていました。
また、これに伴って[SplFixedArray::rewind](https://www.php.net/manual/ja/splfixedarray.rewind)などIterator由来の実装は削除され、かわりに`SplFixedArray::getIterator`が追加されます。

## Standard

### assert() will no longer evaluate string arguments

[assert](https://www.php.net/manual/ja/function.assert)の引数を文字列表現で渡すことができなくなりました。

```php
assert('$a');

// PHP8.0
true
// PHP7.4
Notice:  Undefined variable: a
```

PHP7.4までは、引数が文字列のときはPHPコードとして解釈されていました。
つまりevalされていたってことです。

PHP8では`'$a'`という単なる文字列として扱われます。

### parse_str() can no longer be used without specifying a result array

[parse_str](https://www.php.net/manual/ja/function.parse-str)の第二引数`$result`が必須になりました。
上の方にあるmb_parse_strと全く同じ理由です。

### fgetss() has been removed

[fgetss](https://www.php.net/manual/ja/function.fgetss)は削除されました。

### The string.strip_tags filter has been removed

[文字列フィルタstring.strip_tags](https://www.php.net/manual/ja/filters.string.php)が削除されました。
fgetssなどと同様、何かをするのと同時に文字列をフィルタするのは事故の元なのでやめましょうという方向です。

### The needle argument of strpos(), strrpos(), stripos(), strripos(), strstr(), strchr(), strrchr(), and stristr() will now always be interpreted as a string

[strpos](https://www.php.net/manual/ja/function.strpos)ほかの関数で、引数`$needle`に空文字列が有効になりました。

```php
echo strpos('abc', '');

// PHP8.0
0
// PHP7.4
Warning:  strpos(): Empty needle
```

空文字はどのような文字列にも該当するので、だいたいは1文字目すなわち0になります。

### The length argument for substr(), substr_count(), substr_compare(), and iconv_substr() can now be null

[substr](https://www.php.net/manual/ja/function.substr)、[substr_count](https://www.php.net/manual/ja/function.substr-count)、[substr_compare](https://www.php.net/manual/ja/function.substr-compare)、[iconv_substr](https://www.php.net/manual/ja/function.iconv-substr.php)の引数`$length`にnullを渡した時の挙動が変わりました。

```php
echo substr('abcde', 2, null);

// PHP8.0
"cde"
// PHP7.4
""
```

これまでは返り値が0やら""やらになっていたのですが、これが未指定の場合と同じ動きになります。

### The length argument for array_splice() can now be null

[array_splice](https://www.php.net/manual/ja/function.array-splice.php)の引数`$length`にnullを渡した時の挙動が変わりました。

```php
$input = [1, 2, 3, 4];
array_splice($input, 2, null);
var_dump($input);

// PHP8.0
[1, 2]
// PHP7.4
[1, 2, 3, 4]
```

これまでは何もしませんでしたが、未指定の場合と同じ動きになります。
すなわち、引数`$offset`より後ろが全て削除されます。

### The args argument of vsprintf(), vfprintf(), and vprintf() must now be an array

[vsprintf](https://www.php.net/manual/ja/function.vsprintf)、[vfprintf](https://www.php.net/manual/ja/function.vfprintf)、[vprintf](https://www.php.net/manual/ja/function.vprintf)の引数`$arg`が配列しか受け付けなくなりました。

```php
echo vsprintf('a%sc', 'b');

// PHP8.0
Fatal error:  Uncaught TypeError: vsprintf(): Argument #2 ($values) must be of type array, string given
// PHP7.4
abc
```

元からマニュアルでは配列のみとなっていたのに、何故か文字列なども受け付けていたという謎のサービスでした。


### The 'salt' option of password_hash() is no longer supported

[password_hash](https://www.php.net/manual/ja/function.password-hash)のオプション[salt](https://www.php.net/manual/ja/password.constants.php)が削除されました。
指定する意味はないし固定すると脆弱になるだけなので、元々存在する必要のないオプションです。

### The quotemeta() function will now return an empty string if an empty string was passed

[quotemeta](https://www.php.net/manual/ja/function.quotemeta)にから文字列""を渡すと空文字列""を返すようになりました。
これまではfalseでした。

### hebrevc() / convert_cyr_string() / money_format() / ezmlm_hash() / restore_include_path() has been removed

以下の関数が削除されました。
[hebrevc](https://www.php.net/manual/ja/function.hebrevc)
[convert_cyr_string](https://www.php.net/manual/ja/function.convert-cyr-string)
[money_format](https://www.php.net/manual/ja/function.money-format)
[ezmlm_hash](https://www.php.net/manual/ja/function.ezmlm-hash)
[restore_include_path](https://www.php.net/manual/ja/function.restore-include-path)

上位互換が存在する、他の関数と整合性がないなどの理由で、[PHP7.4で非推奨](https://qiita.com/rana_kualu/items/dfb52b4ff639ae105fa4)となっています。

### get_magic_quotes_gpc() and get_magic_quotes_runtime() has been removed

旧時代PHPの黒歴史のひとつ、[get_magic_quotes_gpc](https://www.php.net/manual/ja/function.get-magic-quotes-gpc)と[get_magic_quotes_runtime](https://www.php.net/manual/ja/function.get-magic-quotes-runtime)が削除されました。
同時に定数FILTER_SANITIZE_MAGIC_QUOTESも削除されました。

PHPはついに、[マジッククオート](https://www.php.net/manual/ja/security.magicquotes.php)の軛から完全に解き放たれたのです。

### Calling implode() with parameters in a reverse order ($pieces, $glue) is no longer supported

[implode](https://www.php.net/manual/ja/function.implode)は歴史的理由から引数を逆順でも受け付けていたのですが、これが削除されました。

```php
echo implode(['a', 'b', 'c'], '|');

// PHP8.0
Fatal error:  Uncaught TypeError: implode(): Argument #2 ($array) must be of type ?array, string given
// PHP7.4
a|b|c
```

PHP8.0は、負の遺産の清算が目立ちます。

### parse_url() will now distinguish absent and empty queries and fragments

[parse_url](https://www.php.net/manual/ja/function.parse-url)の、空のクエリやフラグメントへの返り値が微妙に変わりました。

```php
// 出力のscheme等は省略
var_dump(
    parse_url('http://example.com/foo'),
    parse_url('http://example.com/foo?'),
    parse_url('http://example.com/foo#'),
    parse_url('http://example.com/foo?#'),
);

// PHP8.0
[], ["query"=>""], ["fragment"=>""], ["query"=>"", "fragment"=>""]
// PHP7.4
[], [], [], []
```

空のクエリには空文字列を出力、クエリ自体がない場合は出力自体行わない、と区別できるようになります。

### var_dump() and debug_zval_dump() will now print floating-point numbers using serialize_precision rather than precision

[var_dump](https://www.php.net/manual/ja/function.var-dump)と[debug_zval_dump](https://www.php.net/manual/ja/function.debug-zval-dump)の浮動小数出力が、ini設定[precision](https://www.php.net/manual/ja/ini.core.php#ini.precision)ではなく[serialize_precision](https://www.php.net/manual/ja/ini.core.php#ini.serialize-precision)を使うようになりました。

```php
ini_set('precision', 1);ini_set('serialize_precision', 100);
var_dump(1.23456789012345678901234567890123456789012345678901234567890);

// PHP8.0
float(1.2345678901234566904321354741114191710948944091796875)
// PHP7.4
float(1)
```

100とか指定してもビット数の制限は越えられないみたい。

### If the array returned by __sleep() contains non-existing properties, these are now silently ignored

マジックメソッド[__sleep](https://www.php.net/manual/ja/language.oop5.magic.php#object.sleep)に存在しないプロパティを返した場合、無視するようになりました。

```php
class FOO{
    private $a = 'a';
    public function __sleep()
    {
        return ['a', 'b'];
    }
}
echo serialize(new FOO());

// PHP8.0
O:3:"FOO":1:{s:6:"FOOa";s:1:"a";} // Warning:  serialize(): "b" returned as member variable from __sleep() but does not exist
// PHP7.4
O:3:"FOO":2:{s:6:"FOOa";s:1:"a";s:1:"b";N;} // Notice:  serialize(): "b" returned as member variable from __sleep() but does not exist
```

これまでは、値がnullのプロパティがセットされていました。

### The default locale on startup is now always "C"

デフォルトの[ロケール](https://www.php.net/manual/ja/function.setlocale.php)が常に"C"になりました。
これまではLC_ALLは"C"で、LC_CTYPEは環境変数LANGから取ってくる、みたいなことになっていました。

### Removed deprecated DES fallback in crypt()

[crypt](https://www.php.net/manual/ja/function.crypt)のSALTフォールバックが削除されました。

```php
echo crypt('str', 'あ');

// PHP8.0
*0
// PHP7.4
▒UYLTFzPe08. // Deprecated:  crypt(): Supplied salt is not valid for DES
```

cryptはSALTの形式によって自動的にハッシュ形式を選択するのですが、これまでは未知のSALTが来た場合は自動的にDESにフォールバックしていました。
今後は失敗します。
ただ失敗といっても例外を出したりせず'*0'という文字列を返してくるのでむしろわかりにくいのでは。

### Calling crypt() without an explicit salt is no longer supported

[crypt](https://www.php.net/manual/ja/function.crypt)の第二引数`$salt`が必須になりました。

```php
echo crypt('str');

// PHP8.0
Fatal error:  Uncaught ArgumentCountError: crypt() expects exactly 2 arguments, 1 given
// PHP7.4
$1$SsnnMRiS$4clL.zBKekzZvryhRYVUP1 // Notice:  crypt(): No salt parameter was specified
```

こちらは非対応SALTとは異なり、致命的エラーになります。

### Sort comparison functions that return true or false will now throw a deprecation warning

ソート関数でtrue/falseを返している場合、非推奨の警告が出るようになりました。
0と等しいか、0より大きいか、0より小さい整数を返す必要があります。

```php
$arr = [2, 1];
usort($arr, fn($a, $b) => $a > $b);
var_dump($arr);

// PHP8.0
[1, 2] // Deprecated:  usort(): Returning bool from comparison function is deprecated
// PHP7.4
[1, 2]
```

### Any functions accepting callbacks that are not explicitly specified to accept parameters by reference will now warn

リファレンスを受け取らないコールバック関数の引数にリファレンスを書いた場合、警告が出るようになりました。

```php
array_filter([1,2], function (&$v) {
    return true;
});

// PHP8.0
Warning:  {closure}(): Argument #1 ($v) must be passed by reference, value given
// PHP7.4
何も出ない
```

多くの関数では既にこうなっていたものの、[array_filter](https://www.php.net/manual/ja/function.array-filter)など一部はそうなってなかったので追加したということのようです。
それに`$v`を書き替えても元の値には影響しないので、`&`を付ける意味は特にないです。

### HTTP stream wrapper as used by functions  now advertises HTTP/1.1 rather than HTTP/1.0

[stream_context_create](https://www.php.net/manual/ja/function.stream-context-create)などで作れる[HTTPストリームラッパー](https://www.php.net/manual/ja/wrappers.http.php)のデフォルトがHTTP1.1になりました。

これまでどおりHTTP1.0を使いたい場合は、コンテキストオプションで指定する必要があります。

```php
$opts = [
    'http'=>[
        'protocol_version'=>'1.0',
    ]
];
$context = stream_context_create($opts);
```


### substr(), mb_substr(), iconv_substr() and grapheme_substr() now consistently clamp out-of-bounds offsets to the string boundary

[substr](https://www.php.net/manual/ja/function.substr.php)、[mb_substr](https://www.php.net/manual/ja/function.mb-substr)、[iconv_substr](https://www.php.net/manual/ja/function.iconv-substr)、[grapheme_substr](https://www.php.net/manual/ja/function.grapheme-substr)が、範囲外の引数にも文字列を返すようになりました。

```php
var_dump(
    substr('abc', 10)
);

// PHP8.0
""
// PHP7.4
false
```

これまではfalseになっていました。

### Populating $http_response_header variable by the HTTP stream wrapper doesn't force rebuilding of symbol table anymore

HTTPストリームラッパーが`$http_response_header`を変更してもシンボルテーブルの再構築が行われなくなりました。

ということらしいけど内部のことはよくわかりません。
きっと詳しい人がなんか教えてくれるはず。

## Sysvmsg

### msg_get_queue() will now return an SysvMessageQueue object rather than a resource

[msg_get_queue](https://www.php.net/manual/ja/function.msg-get-queue)がリソースではなくSysvMessageQueueインスタンスを返すようになりました。

## Sysvsem

### sem_get() will now return an SysvSemaphore object rather than a resource

[sem_get](https://www.php.net/manual/ja/function.sem-get)がリソースではなくSysvSemaphoreインスタンスを返すようになりました。

### The $auto_release parameter of sem_get() was changed to accept bool values rather than int

sem_getの第4引数`$auto_release`の型がintからboolになりました。

## Sysvshm

### shm_attach() will now return an SysvSharedMemory object rather than a resource

[shm_attach](https://www.php.net/manual/ja/function.shm-attach)がリソースではなくSysvSharedMemoryインスタンスを返すようになりました。

## tidy

### The $use_include_path parameter has been removed from tidy_repair_string()

[tidy_repair_string](https://www.php.net/manual/ja/tidy.repairstring.php)の引数`$use_include_path`が削除されました。

元々マニュアルにも載ってなかったんだけど、内部的に使っていたらしいです。

### tidy::repairString() and tidy::repairFile() became static methods

[tidy::repairString](https://www.php.net/manual/ja/tidy.repairstring.php)と[tidy::repairFile](https://www.php.net/manual/ja/tidy.repairfile.php)が静的メソッドになりました。

```php
tidy::repairString('hoge');

// PHP8.0
エラー出ない
// PHP7.4
Fatal error:  Uncaught Error: Non-static method tidy::repairString() cannot be called statically
```

## Tokenizer

### T_COMMENT tokens will no longer include a trailing newline

T_COMMENT[トークン](https://www.php.net/manual/ja/tokens.php)は末尾の改行を含まなくなりました。

```php
$str = '<?php // comment
';
var_dump(
    token_get_all($str)[1][1]
);

// PHP8.0
string(10) "// comment"
// PHP7.4
string(11) "// comment
"
```

### Namespaced names are now represented

名前空間はひとまとまりとして解釈されるようになりました。

```php
// 出力は必要部分のみ
$str = '<?php
namespace FOO\BAR;
';
var_dump(
    token_get_all($str)
);

// PHP8.0
[ [T_NAME_RELATIVE, 'FOO\BAR'] ]
// PHP7.4
[ [T_STRING, 'FOO'], [T_NS_SEPARATOR, '\'], [T_STRING, 'BAR'] ]
```

こちらのほうが名前空間としてわかりやすいですね。

## XML

### xml_parser_create(_ns) will now return an XmlParser object rather than a resource

[xml_parser_create](https://www.php.net/manual/ja/function.xml-parser-create)がリソースではなくXmlParserオブジェクトを返すようになりました。

```php
$parser = xml_parser_create();
xml_parse($parser, '<xml></xml>', true);
var_dump($parser);

// PHP8.0
object(XmlParser)#1
// PHP7.4
resource(4) of type (xml)
```

[XMLパーサ関数](https://www.php.net/manual/ja/ref.xml.php)は、これまでと同じ書き方で透過的に動作します。
また[xml_parser_free](https://www.php.net/manual/ja/function.xml-parser-free)は実質的に何もしません。

## XMLReader

### XMLReader::open() and XMLReader::xml() are now static methods

[XMLReader::open](https://www.php.net/manual/ja/xmlreader.open)と[XMLReader::XML](https://www.php.net/manual/ja/xmlreader.xml)は静的メソッドになりました。

## XMLWriter

### The XMLWriter functions now accept and return, respectively, XMLWriter objects instead of resources

[XMLWriter::openUri](https://www.php.net/manual/ja/function.xmlwriter-open-uri.php)などがリソースではなくXMLWriterオブジェクトを返すようになりました。
[XMLWriter関数](https://www.php.net/manual/ja/ref.xmlwriter.php)は、これまでと同じ書き方で透過的に動作します。

## Zip

### ZipArchive::OPSYS_Z_CPM has been removed

定数[ZipArchive::OPSYS_Z_CPM](https://www.php.net/manual/ja/zip.constants.php)が削除されました。

```php
echo ZipArchive::OPSYS_Z_CPM;

// PHP8.0
Fatal error:  Uncaught Error: Undefined constant ZipArchive::OPSYS_Z_CPM
// PHP7.4
9
```

これ、`ZipArchive::OPSYS_CPM`の誤字です。

## Zlib

### gzgetss() has been removed

[gzgetss](https://www.php.net/manual/ja/function.gzgetss)が削除されました。

### inflate_init() will now return an InflateContext object rather than a resource

[inflate_init](https://www.php.net/manual/ja/function.inflate-init)がリソースではなくInflateContextオブジェクトを返すようになりました。
[inflate_add](https://www.php.net/manual/ja/function.inflate-add.php)などは、これまでと同じ書き方で透過的に動作します。

### deflate_init() will now return a DeflateContext object rather than a resource

[deflate_init](https://www.php.net/manual/ja/function.deflate-init)がリソースではなくDeflateContextオブジェクトを返すようになりました。
[deflate_add](https://www.php.net/manual/ja/function.deflate-add.php)などは、これまでと同じ書き方で透過的に動作します。

### zlib.output_compression is no longer automatically disabled for Content-Type: image/*

ini設定[zlib.output_compression](https://www.php.net/manual/ja/zlib.configuration.php#ini.zlib.output-compression)は、これまでは画像に対しては自動的に無効化されていましたが、その自動無効化がなくなりました。


# New Features

新機能。

この多くは[PHP8.0の新機能](https://qiita.com/rana_kualu/items/fe7998fbe773544d5d25)で紹介しています。

## Core

### Added support for union types

[UNION型](https://qiita.com/rana_kualu/items/fe7998fbe773544d5d25#union-types-v2)が追加されました。

```php
function hoge(int|string $fuga): bool|stdClass {
    if($fuga === 0){return true;}
    return new stdClass;
}
```

関数hogeはint型もしくはstring型を受け取り、bool型もしくはstdClassインスタンスを返します。

### Added WeakMap

[弱いマップ](https://qiita.com/rana_kualu/items/fe7998fbe773544d5d25#weak-maps)です。
メモリが足りなくなったら自動で削除されます。

### Added ValueError class

[ValueError](https://www.php.net/manual/ja/class.valueerror.php)クラスが追加されました。

```php
echo bcadd('1', '2', -1);

// PHP8.0
Fatal error:  Uncaught ValueError: bcadd(): Argument #3 ($scale) must be between 0 and 2147483647
// PHP7.4
3
```

[bcadd](https://www.php.net/manual/ja/function.bcadd)の第三引数は小数点以下の桁数なので、マイナス値は不適切です。
このように、型は合っているけど値が範囲外のときに使われる例外となります。

### Any number of function parameters may now be replaced by a variadic argument

継承時に、異なる型の値を可変長引数でまとめることができるようになりました。

```php
class A{
    public function hoge(int $foo, string $bar, stdClass $baz){}
}
class B extends A{
    public function hoge(...$args){}
}

// PHP8.0
エラー出ない
// PHP7.4
Warning:  Declaration of B::hoge(...$args) should be compatible with A::hoge
```

この場合、シグネチャは継承したクラスのものしか確認しません。
すなわち、`(new B())->hoge(1, 2, 3)`とか書いてもエラーは出ません。

これはいいのか？？？？？？

### "static" (as in "late static binding") can now be used as a return type

[返り値にstaticを書ける](https://qiita.com/rana_kualu/items/fe7998fbe773544d5d25#static-return-type)ようになります。

```php
class Test {
    public function create(): static {
        return new static();
    }
}
```

使い道がよくわからないので誰か解説よろ。

### It is now possible to fetch the class name of an object using `$object::class`

[インスタンスからクラス名を取得](https://qiita.com/rana_kualu/items/fe7998fbe773544d5d25#allow-class-on-objects)できるようになります。

```php
echo (new stdClass)::class;

// PHP8.0
stdClass
// PHP7.4
Fatal error:  Cannot use ::class with dynamic class name
```

### New and instanceof can now be used with arbitrary expressions
### Some consistency fixes to variable syntax have been applied

[デリファレンス可能範囲が拡大](https://wiki.php.net/rfc/variable_syntax_tweaks)されます。


```php
class Foo{
    const BAR = 'Bar';
}
class Bar{
    public static $baz = 'QUX';
}
echo Foo::BAR::$baz;

// PHP8.0
QUX
// PHP7.4
Parse error:  syntax error, unexpected '::'
```

これまでは構文エラーになっていたいくつかの構文が許されるようになります。
このRFCややこしくて正直理解が追い付いてません。

### Added Stringable interface

[Stringableインターフェイス](https://qiita.com/rana_kualu/items/fe7998fbe773544d5d25#stringable)が追加されました。

```php
interface Stringable{
   public function __toString(): string;
}
```

これがあると[__toString()](https://www.php.net/manual/ja/language.oop5.magic.php#object.tostring)可能になるというものですが、これは暗黙的にimplementsされるため、使用する側としては特に気にする必要はありません。

### Traits can now define abstract private methods

traitで[abstract privateメソッドが作成可能](https://qiita.com/rana_kualu/items/fe7998fbe773544d5d25#abstract-trait-method-validation)になりました。

```php
trait FOO {
    abstract private function bar();
}

// PHP8.0
エラー出ない
// PHP7.4
Fatal error:  Abstract function FOO::bar() cannot be declared private
```

### `throw` can now be used as an expression

[throwが式](https://qiita.com/rana_kualu/items/44e87a22957fab4732c3)になりました。

```php
fn() => throw new Exception();

// PHP8.0
エラー出ない
// PHP7.4
Parse error:  syntax error, unexpected 'throw'
```

構文の途中などで気軽に例外を投げられるようになります。

### An optional trailing comma is now allowed in parameter lists

[関数定義に末尾カンマ](https://qiita.com/rana_kualu/items/fe7998fbe773544d5d25#allow-trailing-comma-in-parameter-list)が許可されました。

```php
function foo($a, $b,){}

// PHP8.0
エラー出ない
// PHP7.4
Parse error:  syntax error, unexpected ')'
```

関数を呼び出す方は[PHP7.3から使えていた](https://wiki.php.net/rfc/trailing-comma-function-calls)ので、合わせた対応です。

### It is now possible to write `catch (Exception)` to catch an exception without storing

[例外の変数を明示的に受け取らない](https://qiita.com/rana_kualu/items/7edbe66492a3018d90cf)ことができるようになりました。

```php
try{
    new PDO();
}catch(\Throwable){
    echo "なんかエラー出た";
}

// PHP8.0
なんかエラー出た
// PHP7.4
Parse error:  syntax error, unexpected ')'
```

PDOのエラーメッセージを表示すると脆弱性になる可能性があるので出したくない場合など、例外から来た値を使わずに処理したいという意図を明示できます。


### Added support for mixed type

[mixed型](https://qiita.com/rana_kualu/items/4685f2c7693ce0394fe8)がサポートされました。

```php
function foo(mixed $arg){}
foo(1);
foo('x');
foo(new stdClass());

// PHP8.0
エラー出ない
// PHP7.4
Uncaught TypeError: Argument 1 passed to foo() must be an instance of mixed, int given
```

マニュアルでは見慣れた型名ですね。
var_dumpの引数など、あえて多様な型を受け取りたいときに使います。

### Added support for Attributes

[アトリビュート](https://qiita.com/rana_kualu/items/749c389a275f207a8e58)が追加されました。

```php
#[ExampleAttribute]
function foo(){}
```

Javaでいうアノテーションです。
これまではPHPDocとかで適当に書いていましたが、これがPHPの構文としてパース可能な形で書けるようになります。


### Added support for constructor property promotion

[オブジェクト初期化子](https://qiita.com/rana_kualu/items/122a1da3b6089b125cb0)です。
素直にコンストラクタ引数昇格って言った方がわかりやすい気がしてきた。

```php
class HOGE{
    public function __construct(public int $x){}
}
echo (new HOGE(99))->x;

// PHP8.0
99
// PHP7.4
Parse error:  syntax error, unexpected 'public'
```

コンストラクタ引数に可視性を書くと、自動的に同名のプロパティを作って値を突っ込んでくれます。
定型文をたくさん書く必要があって面倒だった初期化が楽になります。

コンストラクタ以外には使えません。

### Added support for `match` expression

[match式](https://qiita.com/rana_kualu/items/38d2854d0575fb73f56a)が導入されました。

```php
echo match("1"){
    1 => '1だ',
    true => 'trueだ',
    "1" => '"1"だ',
    default => 'どれでもない',
};

// PHP8.0
"1"だ
// PHP7.4
Parse error:  syntax error, unexpected '=>'
```

厳密な比較、フォールスルーしない、返り値を持つ式である、とswitch文の問題の多くを解消した構文です。

### Private methods declared on a parent class no longer enforce any inheritance rules

[privateメソッドが子クラスに影響](https://qiita.com/rana_kualu/items/fe7998fbe773544d5d25#remove-inappropriate-inheritance-signature-checks-on-private-methods)しないようになりました。

```php
class A{ 
    private final function foo(int $arg){}
}
class B extends A{ 
    private function foo(string $agg){}
}

// PHP8.0
Warning:  Private methods cannot be final
// PHP7.4
Fatal error:  Cannot override final method A::foo() 
```

privateメソッドにfinalって書くと継承時に何故かFatal Errorになっていたのですが、これがオーバーライドチェックされないようになります。

かわりにprivateは上書きされないからfinalしなくていいというE_WARNINGが出るようになりました。

### Added support for nullsafe operator

[ヌル安全オペレータ](https://qiita.com/rana_kualu/items/c967d58582ef75e73d7d)が追加されました。

```php
echo null?->foo();

// PHP8.0
NULL
// PHP7.4
Parse error:  syntax error, unexpected '->'
```

ヌル安全オペレータ`?->`は、nullに対してプロパティやメソッドを取り出そうとすると、そこで処理が止まります。

なおnullでなければ止まらないので、`(new stdClass)?->foo()`とか書くと`foo()`が無いってエラーになります。

### Added support for named arguments

[名前付き引数](https://qiita.com/rana_kualu/items/13bc0c30192ee22c1396)がサポートされました。

```php
echo htmlspecialchars(encoding:'UTF-8', string:'>');

// PHP8.0
&gt;
// PHP7.4
Parse error:  syntax error, unexpected ':'
```

引数の多い関数で最後の引数だけ呼んだり、引数の順番を入れ替えたりできます。
また呼び出し側に引数名を書くため、どの引数が何を表しているのか理解しやすくなります。

## Date

### Added DateTime::createFromInterface() and DateTimeImmutable::createFromInterface()

[DateTime::createFromInterface](https://www.php.net/manual/ja/datetime.createfrominterface.php)、[DateTimeImmutable::createFromInterface](https://www.php.net/manual/ja/datetimeimmutable.createfrominterface.php)が追加されました。

```php
echo (DateTime::createFromInterface(new DateTimeImmutable()))->format('Y-m-d');

// PHP8.0
2020-12-01
// PHP7.4
Fatal error:  Uncaught Error: Call to undefined method DateTime::createFromInterface
```

名前からすると[DateTime::createFromImmutable](https://www.php.net/manual/ja/datetime.createfromimmutable.php)のように、DateTimeXXXからDateTimeを作るメソッドだと思われます。
現状ではDateTimeとDateTimeImmutableしかないうえにDateTimeInterfaceをユーザがimplementsすることはできないので意味はありませんが、将来種類が増えたときに役立ちそうです。

### Added the DateTime format specifier "p"

[DateTimeのフォーマット](https://www.php.net/manual/ja/datetime.format.php)に`p`が追加されました。
`P`と同じですが、`+00:00`のときだけ`Z`が返ります。よくわからない。

## Dom

### Introduce DOMParentNode and DOMChildNode

[DOMParentNode、DOMChildNodeが追加](https://wiki.php.net/rfc/dom_living_standard_api)されました。
普段SimpleXMLしか使わないからよくわからない。

## Enchant

### enchant_dict_add / enchant_dict_is_added

[enchant_dict_add](https://www.php.net/manual/ja/function.enchant-dict-add)、[enchant_dict_is_added](https://www.php.net/manual/ja/function.enchant-dict-is-added)が追加されました。

[Enchant](https://www.php.net/manual/ja/book.enchant.php)を実用で使ってる人っているんだろうか。

## FPM

### Added a new option pm.status_listen

[設定pm.status_listen](https://www.php.net/manual/ja/install.fpm.configuration.php)が追加されました。
異なるエンドポイントのステータスを確認できるとかなんとか。

## Hash

### HashContext objects can now be serialized

[HashContext](https://www.php.net/manual/ja/class.hashcontext.php)がシリアライズ可能になりました。

```php
echo serialize(hash_init('md5'));

// PHP8.0
O:11:"HashContext":5…
// PHP7.4
Fatal error:  Uncaught Exception: Serialization of 'HashContext' is not allowed
```

リクエストを超えてハッシュ作成を継続したいとかあるのか？

## Opcache

### If the opcache.record_warnings ini setting is enabled, opcache will record compile-time warnings

ini設定[opcache.record_warnings](https://www.php.net/manual/ja/opcache.configuration.php)を有効にした場合、コンパイル時に発生した警告をして次のアクセス時にも発生させます。

## OpenSSL

### Added Cryptographic Message Syntax (CMS)

[Cryptographic Message Syntax](https://wiki.php.net/rfc/add-cms-support)がサポートされました。

## Standard

### printf() and friends now support the %h and %H format specifiers

[printf](https://www.php.net/manual/ja/function.printf.php)および類似関数が、指定子`%h`・`%H`をサポートしました。
`%g`・`%G`と同じですが、ロケールに関わらず小数点が`.`になります。

```php
setlocale(LC_ALL, 'fr');
echo sprintf('%g - %h', 1.2, 3.4);

// PHP8.0
1,2 -
// PHP7.4
1,2 - 3.4
```

上の方にもあったフランス語問題の対応です。

### printf() and friends now support using "*" as width or precision

[printf](https://www.php.net/manual/ja/function.printf.php)および類似関数が、量指定子`*`をサポートしました。

```php
printf("%.*f", 10, 1.2);

// PHP8.0
1.2000000000
// PHP7.4
f
```

精度を外側から渡すことができます。
これまでも文字列結合などで実現は可能でしたが、簡単に書けるようになります。

### proc_open() now supports pseudo-terminal (PTY) descriptors

[proc_open](https://www.php.net/manual/ja/function.proc-open.php)が疑似ターミナルをサポートしました。

```php
$proc = proc_open('dir', [['pty'], ['pty'], ['pty']], $pipes);

// PHP8.0
Warning:  proc_open(): PTY (pseudoterminal) not supported on this system
// PHP7.4
Warning:  proc_open(): pty pseudo terminal not supported on this system
```

なんにしろWindowsではサポートされてなかった。

### proc_open() now supports socket pair descriptors


[proc_open](https://www.php.net/manual/ja/function.proc-open.php)がソケットをサポートしました。

```php
$proc = proc_open('dir', [['socket'], ['socket'], ['socket']], $pipes);

// PHP8.0
エラー出ない
// PHP7.4
Warning:  proc_open(): socket is not a valid descriptor spec/mode
```

こちらはWindowsでも使えます。

### Sorting functions are now stable

ソート関数が[安定ソート](https://wiki.php.net/rfc/stable_sorting)になりました。

```php
$array = [
    'a' => 1,
    'b' => 1,
];
asort($array);
```

これまではソート後にaとbの位置がどうなっているか保証がなかったのですが、今後はaとbの順番が保たれます。

### array_diff(), array_intersect() and their variations can now be used with a single array as argument

[array_diff](https://www.php.net/manual/ja/function.array-diff)などを引数ひとつで使えるようになりました。

```php
array_diff([1, 2]);

// PHP8.0
エラー出ない
// PHP7.4
Warning:  array_diff(): at least 2 parameters are required, 1 given
```

単独だと意味はないですが、`array_intersect(...$arrays)`のように展開して渡したいときに役立ちます。

### The $flag parameter of ob_implicit_flush() was changed to accept bool values

[ob_implicit_flush](https://www.php.net/manual/ja/function.ob-implicit-flush)の引数`$flag`がbool型になりました。

## Zip

### Extension updated to version 1.19.1

zipエクステンションのバージョンが1.19.1になりました。
と言われてもこれが[libzip](https://github.com/nih-at/libzip)のことかすらよくわからないのですが。

### New ZipArchive::lastId property

[ZipArchive](https://www.php.net/manual/ja/class.ziparchive.php)にlastIdプロパティが追加されました。
最後に追加したファイルのインデックスです。

### Error can be checked after an archive is closed

ZipArchiveを閉じた後でも、ZipArchive::statusなどでステータスを確認可能になりました。

### The remove_path option of ZipArchive::addGlob() and ::addPattern() is now treated as arbitrary string prefix

[ZipArchive::addGlob](https://www.php.net/manual/ja/ziparchive.addglob.php)および[ZipArchive::addPattern](https://www.php.net/manual/ja/ziparchive.addpattern.php)のオプション`remove_path`は、アーカイブを追加する際に削除される接頭辞になりました。
以前はディレクトリ名でしたが、`add_path`と整合が取れていなかったので変更されました。

### Optional compression / encryption features are listed in phpinfo

圧縮/暗号化オプションがphpinfoに表示されるようになりました。

# Changes in SAPI modules

SAPIモジュールへの変更

## Apache

### The PHP module has been renamed

Apache PHPモジュールの名前が`php7_module`から`php_module`に変更されました。

今後メジャーバージョンアップのたびに`LoadModule php8_module`とか書き替えずに済むようになります。

# Deprecated Functionality

非推奨になる機能。
ここで『できなくなった』と書いてあるのは非推奨と読み替えてください。

## Core

### Declaring a required parameter after an optional one is deprecated

省略可能引数の後で必須引数を記述することができなくなりました。

```php
function hoge($foo = 'foo', $bar){}

// PHP8.0
Deprecated:  Required parameter $bar follows optional parameter $foo
// PHP7.4
エラー出ない
```

今まで許可されていたことにびっくりですね。

### Calling get_defined_functions() with $exclude_disabled explicitly set to false is deprecated

[get_defined_functions](https://www.php.net/manual/ja/function.get-defined-functions.php)の引数`$exclude_disabled`にfalse指定ができなくなりました。

互換性のない変更点において、無効化された関数は存在しないものにされました。
そのため、このフラグには意味がなくなりました。

## Enchant

### enchant_broker_set_dict_path and enchant_broker_get_dict_path not available

libenchant-2では、[enchant_broker_set_dict_path](https://www.php.net/manual/ja/function.enchant-broker-set-dict-path.php)と[enchant_broker_get_dict_path](https://www.php.net/manual/ja/function.enchant-broker-get-dict-path)が使えなくなりました。

### enchant_dict_add_to_personal, use enchant_dict_add instead

[enchant_dict_add_to_personal](https://www.php.net/manual/ja/function.enchant-dict-add-to-personal.php)が非推奨になりました。
かわりにenchant_dict_addを使います。

### enchant_dict_is_in_session, use enchant_dict_is_added instead

[enchant_dict_is_in_session](https://www.php.net/manual/ja/function.enchant-dict-is-in-session.php)が非推奨になりました。
かわりにenchant_dict_is_addedを使います。

### enchant_broker_free and enchant_broker_free_dict, unset the object instead

[enchant_broker_free](https://www.php.net/manual/ja/function.enchant-broker-free.php)と[enchant_broker_free_dict](https://www.php.net/manual/ja/function.enchant-broker-free-dict.php)が非推奨になりました。
かわりにunsetを使います。

### ENCHANT_MYSPELL and ENCHANT_ISPELL constants

[定数](https://www.php.net/manual/ja/enchant.constants.php)が非推奨になりました。

## LibXML

### libxml_disable_entity_loader() has been deprecated

[libxml_disable_entity_loader](https://www.php.net/manual/ja/function.libxml-disable-entity-loader)が非推奨になりました。
[XXE脆弱性](https://qiita.com/tomoki0sanaki/items/015b6e8b807ed256a6e4)対応のためです。

## PGSQL / PDO PGSQL

### The constant PG_VERSION_STR has now the same value as PG_VERSION, and thus is deprecated

定数PG_VERSION_STRは中身がPG_VERSIONと同じになり、さらに非推奨になりました。

PG_VERSION_STRもPG_VERSIONも[Postgresの項目](https://www.php.net/manual/ja/pgsql.constants.php)にないんだけど何処で定義されてるんだろう。

### Function aliases in the pgsql extension have been deprecated

Postgres関数の古い呼び名のエイリアスが非推奨になりました。

たとえば[pg_lo_open](https://www.php.net/manual/ja/function.pg-lo-open.php)にはpg_loopenというエイリアスが存在し、PHP7.4までは警告なく使用可能でした。

## Zip

### Using empty file as ZipArchive is deprecated

空のファイルをZipArchiveとして扱うことができなくなりました。
[libzip 1.6.0で非対応になった](https://libzip.org/news/release-1.6.0.html)ためです。

### The procedural API of Zip is deprecated

[手続き型のzip関数](https://www.php.net/manual/ja/ref.zip.php)は非推奨になりました。

```php
zip_open('tmp');

// PHP8.0
Deprecated:  Function zip_open() is deprecated
// PHP7.4
エラー出ない
```

[ZipArchive](https://www.php.net/manual/ja/class.ziparchive.php)を使いましょう。

## Reflection

### ReflectionFunction::isDisabled() is deprecated

[ReflectionFunction::isDisabled](https://www.php.net/manual/ja/reflectionfunction.isdisabled)が非推奨になりました。
無効化された関数は存在しないものにされたためです。

### ReflectionParameter::getClass(), ReflectionParameter::isArray(), and ReflectionParameter::isCallable() are deprecated

[ReflectionParameter::getClass](https://www.php.net/manual/ja/reflectionparameter.getclass.php)、[ReflectionParameter::isArray](https://www.php.net/manual/ja/reflectionparameter.isarray.php)、[ReflectionParameter::isCallable](https://www.php.net/manual/ja/reflectionparameter.iscallable.php)が非推奨になりました。

かわりに[ReflectionParameter::getType](https://www.php.net/manual/ja/reflectionparameter.gettype.php)と[ReflectionType](https://www.php.net/manual/ja/class.reflectiontype.php)を使いましょう。

# Changed Functions

仕様が変更になる関数。

## Reflection

### ReflectionClass::getConstants and ReflectionClass::getReflectionConstants results can be now filtered

[https://www.php.net/manual/ja/reflectionclass.getconstants](https://www.php.net/manual/ja/reflectionclass.getconstants)と[ReflectionClass::getReflectionConstants](https://www.php.net/manual/ja/reflectionclass.getreflectionconstants.php)に引数`$filter`が追加されました。
またフィルタ用の定数`ReflectionClassConstant::[IS_PUBLIC|IS_PROTECTED|IS_PRIVATE]`が追加されました。

```php
class FOO{
    public const A = 'A';
    protected const B = 'B';
    private const C = 'C';
}
$c = (new ReflectionClass('FOO'))->getReflectionConstants(filter:ReflectionClassConstant::IS_PRIVATE);
// privateの定数Cだけ出てくる
```

引数未指定のときはこれまでどおり全て出てきます。

## Zip

### ZipArchive::addGlob and ZipArchive::addPattern methods accept more values in the "options"

[ZipArchive::addGlob](https://www.php.net/manual/ja/ziparchive.addglob.php)と[ZipArchive::addPattern](https://www.php.net/manual/ja/ziparchive.addpattern.php)の引数`$options`に対象が追加されました。

- flags
- comp_method
- comp_flags
- env_method
- enc_password

### ZipArchive::addEmptyDir, ZipArchive::addFile and aZipArchive::addFromString methods have a new "flags" argument

[ZipArchive::addEmptyDir](https://www.php.net/manual/ja/ziparchive.addemptydir)、[ZipArchive::addFile](https://www.php.net/manual/ja/ziparchive.addfile)、[ZipArchive::addFromString](https://www.php.net/manual/ja/ziparchive.addfromstring)に引数`$flags`が追加されました。

### ZipArchive::extractTo now restore file modification time

[ZipArchive::extractTo](https://www.php.net/manual/ja/ziparchive.extractto)がmtimeを復元するようになりました。
これまでは解凍した時刻になっていました。

# New Functions

新しい関数。

## Core

### Added get_resource_id($resource) function

関数[get_resource_id](https://www.php.net/manual/ja/function.get-resource-id.php)が追加されました。

```php
echo get_resource_id(tmpfile()); // 4 環境によって変わる
```

リソースのリソースIDを取得できます。
`(int)$resource`と同じですが、関数的に記述することができます。

## ldap_count_references

関数[ldap_count_references](https://www.php.net/manual/ja/function.ldap-count-references.php)が追加されました。

よくわかりませんが、おそらく[WindowsAPI](https://docs.microsoft.com/ja-jp/windows/win32/api/winldap/nf-winldap-ldap_count_references)などと同じものでしょう。
他の[LDAP関数](https://www.php.net/manual/ja/ref.ldap.php)も[ほぼ共通](https://docs.microsoft.com/ja-jp/windows/win32/api/winldap/)ですし。

## OpenSSL

### Added openssl_cms_encrypt() / openssl_cms_decrypt() / openssl_cms_read() / openssl_cms_sign() / openssl_cms_verify()

CMS関連の関数が追加されました。
[Cryptographic Message Syntax](https://wiki.php.net/rfc/add-cms-support)サポートに伴い導入されたものです。

```php
openssl_cms_encrypt('input.txt', 'output.txt', file_get_contents('key.pem'), []);
```

使い方は[openssl_pkcs7_XXXXX](https://www.php.net/manual/ja/function.openssl-pkcs7-encrypt.php)と相似です。

## PCRE

### Added preg_last_error_msg

[preg_last_error_msg](https://www.php.net/manual/ja/function.preg-last-error-msg)が追加されました。

```php
preg_match('/(?:\D+|<\d+>)*[!?]/', 'foobar foobar foobar');
echo preg_last_error_msg(); // Backtrack limit exhausted
```

正規表現で最後に発生したエラーメッセージを返します。
意味的には[preg_last_error](https://www.php.net/manual/ja/function.preg-last-error)と同じですが、こちらはintでわかりにくいため、メッセージとして出力するようにしたものです。

## SQLite3

### Add SQLite3::setAuthorizer() and respective class constants

[SQLite3::setAuthorizer](https://www.php.net/manual/ja/sqlite3.setauthorizer.php)が追加されました。

SQLを実行するたびに呼ばれるコールバックを設定することができます。

## Standard

### str_contains / str_starts_with / str_ends_with

[str_contains](https://www.php.net/manual/ja/function.str-contains.php)、[str_starts_with](https://www.php.net/manual/ja/function.str-starts-with.php)、[str_ends_with](https://www.php.net/manual/ja/function.str-ends-with.php)が追加されました。

```php
str_contains('森久保乃々', '森久保'); // true
str_starts_with('望月聖', '望月'); // true
str_ends_with('イヴ・サンタクロース', 'サンタクロース'); // true
```

それぞれ[○○が含まれる](https://qiita.com/rana_kualu/items/cb758cdc21d60e632491)、[○○で始まる/終わる](https://qiita.com/rana_kualu/items/71e2980da92b49736001)、の文字列検索を楽にする関数です。

### Added fdiv() function

[fdiv](https://www.php.net/manual/ja/function.fdiv.php)が追加されました。

```php
echo fdiv(1, 0); // INF
```

IEEE 754に準拠した割り算です。

### Added get_debug_type() function

[get_debug_type](https://www.php.net/manual/ja/function.get-debug-type.php)が追加されました。

```php
echo get_debug_type(1), get_debug_type(new DateTime()); // int, DateTime
```

プリミティブ型の型名を返す[gettype](https://www.php.net/manual/ja/function.gettype)と、オブジェクトのクラス名を返す[get_class](https://www.php.net/manual/ja/function.get-class.php)の[悪魔合体](https://qiita.com/rana_kualu/items/aa4438e57e2ed8112c60)です。

## Zip

### ZipArchive::setMtimeName and ZipArchive::setMtimeIndex

[ZipArchive::setMtimeName](https://www.php.net/manual/ja/ziparchive.setmtimename)と[ZipArchive::setMtimeIndex](https://www.php.net/manual/ja/ziparchive.setmtimeindex.php)が追加されました。
mtimeを操作できます。

### ZipArchive::setProgressCallback / ZipArchive::setCancelCallback

ZipArchive::setProgressCallbackとZipArchive::setCancelCallbackが追加されました。

ってUPGRADINGには書いてあるんだけど、試してみるとCall to undefinedって言われるし[registerProgressCallback](https://www.php.net/manual/ja/ziparchive.registerprogresscallback.php)と[registerCancelCallback](https://www.php.net/manual/ja/ziparchive.registercancelcallback.php)が存在するのでおそらく間違い。

### ZipArchive::replaceFile

[ZipArchive::replaceFile](https://www.php.net/manual/ja/ziparchive.replacefile.php)が追加されました。
中身のファイルの一部を置き換えるみたいだけど、そんなややこしいことをPHPで行うことはあるのだろうか。

### ZipArchive::isCompressionMethodSupported / ZipArchive::isEncryptionMethodSupported

[ZipArchive::isCompressionMethodSupported](https://www.php.net/manual/ja/ziparchive.iscompressionmethoddupported.php)と[ZipArchive::isEncryptionMethodSupported](https://www.php.net/manual/ja/ziparchive.isencryptionmethoddupported.php)が追加されました。

名前のとおり、圧縮方式および暗号化方式をサポートしているか確認できます。

# New Classes and Interfaces

新しいクラス、インターフェイス。

## Tokenizer

### PhpToken

[PhpToken](https://wiki.php.net/rfc/token_as_object)クラスが追加されました。

```php
echo PhpToken::tokenize('<?php echo; ?>')[0]->text; // <?php
```

既存の[Tokenizer](https://www.php.net/manual/ja/book.tokenizer.php)をオブジェクト的に扱えるようにしたものです。


# Removed Extensions and SAPIs

削除されたエクステンション、SAPIなど。

## XML-RPC

### The xmlrpc extension has been unbundled and moved to PECL

[XML-RPC](https://www.php.net/manual/ja/book.xmlrpc.php)がPHPコアから削除され、PECL行きになりました。
内部で使っている[xmlrpc-epi](https://sourceforge.net/projects/xmlrpc-epi/)が[開発放棄されている](https://sourceforge.net/projects/xmlrpc-epi/files/xmlrpc-epi-base/)ためです。

# Other Changes to Extensions

そのほかの変更点。

## CURL

### The CURL extension now requires at least libcurl 7.29.0

Curlエクステンションが[libcurl](https://curl.se/libcurl/)の7.29.0以上を必要とするようになりました。

### curl_init() will now return a CurlHandle object rather than a resource

[curl_init](https://www.php.net/manual/ja/function.curl-init.php)はリソースではなくCurlHandleオブジェクトを返すようになりました。

```php
var_dump(
    curl_init()
);

// PHP8.0
object(CurlHandle)#1
// PHP7.4
resource(4) of type (curl)
```

他のCurl関数はこれまでと同じ書き方で透過的に動作します。
[curl_close](https://www.php.net/manual/ja/function.curl-close.php)は実質的に何もしなくなりました。

### curl_multi_init() will now return a CurlMultiHandle object rather than a resource

[curl_multi_init](https://www.php.net/manual/ja/function.curl-multi-init.php)はリソースではなくCurlMultiHandleオブジェクトを返すようになりました。

それ以外はcurl_initとほぼ同じです。

### curl_share_init() will now return a CurlShareHandle object rather than a resource

[curl_share_init](https://www.php.net/manual/ja/function.curl-share-init.php)はリソースではなくCurlShareHandleオブジェクトを返すようになりました。

それ以外はcurl_initとほぼ同じです。

### The deprecated parameter `$version` of curl_version() has been removed

非推奨だった[curl_version](https://www.php.net/manual/ja/function.curl-version.php)の第一引数`$version`が削除されました。

マニュアルからは既に抹消されています。

## Date

### DatePeriod now implements IteratorAggregate

[DatePeriod](https://www.php.net/manual/ja/class.dateperiod.php)が[IteratorAggregate](https://www.php.net/manual/ja/class.iteratoraggregate.php)をimplementsするようになりました。

```php
(new ReflectionClass('DatePeriod'))->getInterfaceNames(); // [IteratorAggregate, Traversable]
```

以前は[Traversable](https://www.php.net/manual/ja/class.traversable.php)でした。

## DOM

### DOMNamedNodeMap / DOMNodeList now implements IteratorAggregate

[DOMNamedNodeMap](https://www.php.net/manual/ja/class.domnamednodemap.php)および[DOMNodeList](https://www.php.net/manual/ja/class.domnodelist.php)が[IteratorAggregate](https://www.php.net/manual/ja/class.iteratoraggregate.php)をimplementsするようになりました。
これらも以前は[Traversable](https://www.php.net/manual/ja/class.traversable.php)でした。

## Intl

### IntlBreakIterator / ResourceBundle now implements IteratorAggregate


[IntlBreakIterator](https://www.php.net/manual/ja/class.intlbreakiterator.php)および[ResourceBundle](https://www.php.net/manual/ja/class.resourcebundle.php)が[IteratorAggregate](https://www.php.net/manual/ja/class.iteratoraggregate.php)をimplementsするようになりました。
以前は[Traversable](https://www.php.net/manual/ja/class.traversable.php)でした。

## Enchant

### The enchant extension now uses libenchant-2 by default when available

[Enchant](https://www.php.net/manual/ja/book.enchant.php)エクステンションが使用しているlibenchantのバージョンがlibenchant-2になりました。
1系は非推奨となり、将来的に削除されます。

## GD

### The $num_points parameter of imagepolygon(), imageopenpolygon() and imagefilledpolygon() is now optional

[imagepolygon](https://www.php.net/manual/ja/function.imagepolygon)、[imageopenpolygon](https://www.php.net/manual/ja/function.imageopenpolygon)、[imagefilledpolygon](https://www.php.net/manual/ja/function.imagefilledpolygon)の引数`$num_points`が省略可能になりました。
省略した場合、`$points / 2`とみなされます。

```php
imagepolygon( $im=imagecreatetruecolor(100, 100), [1,2,3,4,5,6], imagecolorallocate($im, 255,255,255))
```

第四引数`$color`は省略不可のため、省略する場合は第三引数に`$color`を入れる、すなわち引数の数によって第三引数の意味が変わるという非常にわかりにくいことになります。
負債を増やしてどうする。

```php
imagepolygon( $im=imagecreatetruecolor(100, 100), [1,2,3,4,5,6], null, imagecolorallocate($im, 255,255,255));
// Fatal error:  Uncaught ValueError: imagepolygon(): Argument #3 ($num_points_or_color) must be greater than or equal to 3

imagepolygon( $im=imagecreatetruecolor(100, 100), points:[1,2,3,4,5,6], color:imagecolorallocate($im, 255,255,255))
// Fatal error:  Uncaught ArgumentCountError: imagepolygon(): Argument #3 ($num_points_or_color) not passed
```

nullにしたり名前付き引数で飛ばしたりといったこともできません。
これはもっとどうにかしたほうがよかったのでは。

### The function imagegetinterpolation() to get the current interpolation method has been added

[imagegetinterpolation](https://www.php.net/manual/ja/function.imagegetinterpolation.php)が追加されました。

```php
$im=imagecreatetruecolor(100, 100);
imagesetinterpolation($im, IMG_GENERALIZED_CUBIC);
echo imagegetinterpolation($im); // 11
```

現在設定されている[補間方法](https://www.php.net/manual/ja/function.imagesetinterpolation.php)を取得します。

## JSON

### The JSON extension cannot be disabled anymore

JSONエクステンションを無効にすることができなくなりました。

[マニュアル](https://www.php.net/manual/ja/book.json.php)には全く載っていないのですが、実はこれまでコンパイルオプション`--disable-json`で無効化することが可能でした。

## MBString

### The Unicode data tables have been updated to version 13.0.0

[Unicodeデータベース](https://unicode.org/reports/tr44/)が13.0.0にバージョンアップされました。

## PDO

### PDOStatement now implements IteratorAggregate

[PDOStatement](https://www.php.net/manual/ja/class.pdostatement.php)が[IteratorAggregate](https://www.php.net/manual/ja/class.iteratoraggregate.php)をimplementsするようになりました。
以前は[Traversable](https://www.php.net/manual/ja/class.traversable.php)でした。

## LibXML

### The minimum required libxml version is now 2.9.0

要求する[libxml](http://www.xmlsoft.org/)がバージョン2.9.0以上になりました。

以前は2.6.0以上でした。

## MySQLi / PDO MySQL

### When mysqlnd is not used the minimum supported libmysqlclient version is now 5.5

要求するlibmysqlclientのバージョンが5.5以上になりました。
libmysqlclientではなく[mysqlnd](https://www.php.net/manual/ja/book.mysqlnd.php)を使う場合は不要です。

ところで[マニュアル](https://www.php.net/manual/ja/mysqlinfo.library.choosing.php)には『mysqlndを勧める』って書いてあるんだけど、変更履歴では『libmysqlclientが推奨だしデフォルトもこっち』って書いてあるんですよね。
どっちが正解なんだ。

### mysqli_result now implements IteratorAggregate

[mysqli_result](https://www.php.net/manual/ja/class.mysqli-result.php)が[IteratorAggregate](https://www.php.net/manual/ja/class.iteratoraggregate.php)をimplementsするようになりました。
以前は[Traversable](https://www.php.net/manual/ja/class.traversable.php)でした。

## PGSQL / PDO PGSQL

### The PGSQL and PDO PGSQL extensions now require at least libpq 9.1

要求する[libpq](https://www.postgresql.jp/document/9.1/html/libpq.html)のバージョンが9.1以上になりました。

## Readline

### Calling readline_completion_function() before the interactive prompt starts will now override the default interactive prompt completion function

[readline_completion_function](https://www.php.net/manual/ja/function.readline-completion-function)は、対話型シェルが起動していないときにも動くようになりました。
以前は、既に対話型シェルが起動していないと動きませんでした。

## SimpleXML

### SimpleXMLElement now implements RecursiveIterator and absorbed the functionality of SimpleXMLIterator

[SimpleXMLElement](https://www.php.net/manual/ja/class.simplexmlelement.php)が[RecursiveIterator](https://www.php.net/manual/ja/class.recursiveiterator.php)をimplementsするようになりました。
以前は[Traversable](https://www.php.net/manual/ja/class.traversable.php)でした。

さらに[SimpleXMLIterator](https://www.php.net/manual/ja/class.simplexmliterator.php)の機能を吸収しました。
SimpleXMLIteratorは実質的にSimpleXMLElementと同じになりました。

## Shmop

### shmop_open() will now return a Shmop object rather than a resource

[shmop_open](https://www.php.net/manual/ja/function.shmop-open)はリソースではなくShmopオブジェクトを返すようになりました。

他の共有メモリ関数はこれまでと同じ書き方で透過的に動作します。
[shmop_close](https://www.php.net/manual/ja/function.shmop-close.php)は実質的に何もしなくなります。

# New Global Constants

新たなグローバル定数。

## Filter

### FILTER_VALIDATE_BOOL has been added as an alias for FILTER_VALIDATE_BOOLEAN

[検証フィルタ](https://www.php.net/manual/ja/filter.filters.validate.php)FILTER_VALIDATE_BOOLが追加されました。

```php
var_dump(FILTER_VALIDATE_BOOL, FILTER_VALIDATE_BOOLEAN); // 258, 258
```

これはFILTER_VALIDATE_BOOLEANのエイリアスです。
真偽型の表記は`bool`に揃えられつつあるので、他の`boolean`もいずれ`bool`に変更されるでしょう。


# Changes to INI File Handling

iniファイルの変更。

## zend.exception_string_param_max_len

ini設定`zend.exception_string_param_max_len`が[追加されました](https://qiita.com/rana_kualu/items/fe7998fbe773544d5d25#configurable-string-length-in-gettraceasstring)。
[スタックトレース](https://www.php.net/manual/ja/throwable.gettraceasstring.php)に表示される引数の文字数を制御します。

```php
try {
    substr('12345678901234567890');
} catch(Throwable $e) {
    echo $e->getTraceAsString();
}

// zend.exception_string_param_max_len=15のとき
#0 C:\xampp\htdocs\test.php(10): substr('123456789012345...')

// zend.exception_string_param_max_len=1のとき
#0 C:\xampp\htdocs\test.php(6): substr('1...')
```

開発時のデバッグなどに重宝するでしょう。

デフォルトは15で、範囲は0から1000000です。
[ini_set](https://www.php.net/manual/ja/function.ini-set)で変更できたので[PHP_INI_ALL](https://www.php.net/manual/ja/configuration.changes.modes.php)のようです。

### com.dotnet_version

[dotnet](https://www.php.net/manual/ja/book.com.php)を使う際の.netフレームワークのバージョンを指定できるようです。


# Windows Support

## Standard

### Program execution functions using the shell now consistently execute `%comspec% /s /c "$commandline"`,

[exec](https://www.php.net/manual/ja/function.exec)などのシェルコマンド実行関数が、一貫して`%comspec% /s /c "$commandline"`という形で実行されるようになりました。

ということらしいですがよくわかりません。

## GD

### php_gd2.dll has been renamed to php_gd.dll

GDエクステンションのファイル名が`php_gd2.dll`から`php_gd.dll`に変更されました。

## php-test-pack

### The test runner has been renamed from run-test.php to run-tests.php

[テストパッケージ](https://windows.php.net/download/)のテストランナーファイル名が`run-test.php`から`run-tests.php`に変更されました。

# Other Changes

その他の変更点

## EBCDIC targets are no longer supported

文字コード[EBCDIC](https://ja.wikipedia.org/wiki/EBCDIC)がサポート対象外になりました。

果たして使っていた人はいるのだろうか？


# Performance Improvements

パフォーマンスについて。

## A Just-In-Time (JIT) compiler has been added to the opcache extension

[JIT](https://qiita.com/rana_kualu/items/ba312d2789bd228f887a)がサポートされました。

```php
function getFibonacci(int $i){
    return $i < 2 ? $i : getFibonacci($i-1) + getFibonacci($i-2);
}

$a = microtime(true);
echo getFibonacci(38);
$b = microtime(true);
echo $b - $a;
```

| PHP8デフォルト | opcache有効 | JIT有効 |
|---|---|---|---|
| 6.931639 | 5.833915 | 1.698887 |
| 7.443145 | 5.536612 | 2.009317 |
| 6.610769 | 5.619338 | 1.662739 |
| 6.794568 | 5.654112 | 1.739347 |
| 7.286194 | 5.774223 | 1.788053 |

CPUバウンドな処理はとんでもない速さになります。

ただPHPの主な用途はディスクやデータベースへのIOで、それらにはJITの恩恵はほぼないので、実際のWebアプリケーションはここまで極端に速くはなりません。
[公式LP](https://www.php.net/releases/8.0/en.php)ではざっくり1割から3割減というところですね。
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/892321b6-3afa-f278-c951-f29201ab586f.png)



# 感想

変更点多すぎ！！！！
[PHP8たいしたことないんじゃねえの](https://qiita.com/rana_kualu/items/993fff9662726a004660)とか言ってた奴土下座な。

互換性のない変更の多くは、古くからのアバウトな仕様を排除し、厳密な書き方を推奨する方向に向けるものです。
implodeの引数が逆順でも書けるなんてのはその最たるものですね。
そのぶん昔からの熟成されたソースを使っているところは移行が大変になると思いますが、PHPは互換を切ってでも進化し続ける方向を選んだということなので、まあがんばってもらいましょう。
それにPHP7以降の近代風な書き方をしている限りでは、変更が必要なところはほとんどありません。

そして新機能については、流行りの書式やら文法などを貪欲に取り入れていて、このあたりはさすがPHPってところです。
節操がないとも言えますが、その節操のなさこそがPHPたる所以と言えましょう。
アロー関数や型宣言、アトリビュートあたりはまだ機能が半端なので、次のメジャーバージョンかあるいはマイナーバージョンでさらに進化しそうですね。

さらにJITが入ったことで、Webアプリケーションだけに囚われない、実用的な計算ライブラリでもPHPが輝く時代がやってくるかもしれません。
まあC++やGoあたりとはさすがに比べものにはならないですが、他のスクリプト言語に比べればだいぶいい線行っているのではないでしょうか。