## 文字列

string は、文字が連結されたものです。PHP では、 文字は 1 バイトと同じです。つまり、256 個の異なる文字を使用可能です。 これは、PHP が Unicode をネイティブにサポートしていないことも意味します。 文字列型の詳細を参照ください。

> 注意: 32bit ビルドでは、 文字列の最大長は 2GB (2147483647 バイト) です。

### 構文

文字列リテラルは、4 つの異なる方法で指定することが可能です。

- 引用符
- 二重引用符
- ヒアドキュメント構文
- Nowdoc 構文

#### 引用符

文字列を指定する最も簡単な方法は、引用符 (文字 `'`) で括ることです。

引用符をリテラルとして指定するには、バックスラッシュ (`\`) でエスケープする必要があります。 バックスラッシュをリテラルとして指定するには、二重 (`\\`) にします。 それ以外の場面で登場するバックスラッシュは、すべてバックスラッシュそのものとして扱われます。 つまり、`\r` や `\n` といったおなじみのエスケープシーケンスを書いても特別な効果は得られず、 書いたままの形式で出力されます。

> 注意: ダブルクォート 構文や ヒアドキュメント構文 とは異なり、 変数と特殊文字のエスケープシーケンスは、 引用符 (シングルクオート) で括られた文字列にある場合には展開されません。

例1 Syntax Variants

    <?php
    echo 'this is a simple string', PHP_EOL;

    echo 'You can also have embedded newlines in
    strings this way as it is
    okay to do', PHP_EOL;

    // 出力: Arnold once said: "I'll be back"
    echo 'Arnold once said: "I\'ll be back"', PHP_EOL;

    // 出力: You deleted C:\*.*?
    echo 'You deleted C:\\*.*?', PHP_EOL;

    // 出力: You deleted C:\*.*?
    echo 'You deleted C:\*.*?', PHP_EOL;

    // 出力: This will not expand: \n a newline
    echo 'This will not expand: \n a newline', PHP_EOL;

    // 出力: Variables do not $expand $either
    echo 'Variables do not $expand $either', PHP_EOL;
    ?>

#### 二重引用符

文字列が二重引用符 (`"`) で括られた場合、 PHP は、以下のエスケープシーケンスを特殊な文字として解釈します。

エスケープされた文字
記述 | 意味
--- | ---
`\n` | ラインフィード (LF またはアスキーの 0x0A (10))
`\r` | キャリッジリターン (CR またはアスキーの 0x0D (13))
`\t` | 水平タブ (HT またはアスキーの 0x09 (9))
`\v` | 垂直タブ (VT またはアスキーの 0x0B (11))
`\e` | エスケープ (ESC あるいはアスキーの 0x1B (27))
`\f` | フォームフィード (FF またはアスキーの 0x0C (12))
`\\` | バックスラッシュ
`\$` | ドル記号
`\"` | 二重引用符
`\[0-7]{1,3}` | 8進数: 正規表現 `[0-7]{1,3}` にマッチする文字シーケンスは、8 進数表記の 1 文字 (例:. `"\101" === "A"`) です。 正規表現にマッチする文字シーケンスは、8 進数表記の 1 文字です。 1 バイトに収まらない部分は、何もメッセージを出さずにオーバーフローします (例: `"\400" === "\000"`) 。
`\x[0-9A-Fa-f]{1,2}` | 16進数: 正規表現 `[0-9A-Fa-f]{1,2}` にマッチする文字シーケンスは、16 進数表記の 1 文字(例: `"\x41" === "A"`)です。
`\u{[0-9A-Fa-f]+}` | Unicode: 正規表現 `[0-9A-Fa-f]+` にマッチする文字シーケンスは、Unicode のコードポイントです。 そのコードポイントの UTF-8 表現を文字列として出力します。 シーケンスを波括弧で囲む必要があります。例 `"\u{41}" === "A"`

繰り返しますが、この他の文字をエスケープしようとした場合には、 バックスラッシュも出力されます!

しかし、二重引用符で括られた文字列で最も重要なのは、 変数名が展開されるところです。詳細は、文字列の補間を参照ください。

#### ヒアドキュメント

文字列を区切る別の方法としてヒアドキュメント構文 ("<<<") があります。この場合、ある ID (と、それに続けて改行文字) を `<<<` の後に指定し、文字列を置いた後で、 同じ ID (終端ID) を括りを閉じるために置きます。

終端ID は、スペースまたはタブでインデントできます。 その場合、インデントされた部分は文字列の全ての行から取り除かれます。 PHP 7.3.0 より前のバージョンでは、 終端ID はその行の最初のカラムから始めなければ いけませんでした。

また、終端ID は、PHP の他のラベルと同様の命名規則に従う必要があります。 つまり、英数字およびアンダースコアのみを含み、 数字でない文字またはアンダースコアで始まる必要があります。

例2 PHP 7.3.0 以降での、基本的なヒアドキュメントの使い方

    <?php
    // 終端IDをインデントしない場合
    echo <<<END
          a
         b
        c
    \n
    END;
    // 終端IDを4つのスペースでインデントする場合
    echo <<<END
          a
         b
        c
        END;

上の例の PHP 7.3 での出力は、このようになります。

          a
         b
        c
      a
     b
    c

終端ID が、文字列のいずれかの行より奥にインデントされている場合、 ParseError がスローされます。

例3 終端ID は 文字列本体よりも奥にインデントしてはいけない

    <?php
    echo <<<END
      a
     b
    c
       END;

上の例の PHP 7.3 での出力は、このようになります。

    Parse error: Invalid body indentation level (expecting an indentation level of at least 3) in example.php on line 4

終端ID をインデントする場合、 インデントに使う文字として、タブまたはスペースが使えます。 しかし、終端ID、および (終端ID までの)文字列の本体どちらであっても、 インデントする際にタブとスペースを混ぜては いけません。 混ぜた場合、 ParseError がスローされます。 インデントに使う文字に制限があるのは、 タブとスペースを混ぜてしまうと可読性が損なわれるためです。

例4 文字列本体 や 終端ID のインデントに違う文字を使う

    <?php
    // 以下のコードはいずれも動作しません。
    // 文字列本体(スペース) と 終端ID(タブ) とで、異なる文字でインデントする
    {
        echo <<<END
         a
            END;
    }
    // 文字列本体に、タブとスペースを混ぜてインデントする
    {
        echo <<<END
            a
         END;
    }
    // 終端IDのインデントに、スペースとタブを混ぜる
    {
        echo <<<END
              a
             END;
    }

上の例の PHP 7.3 での出力は、このようになります。

    Parse error: Invalid indentation - tabs and spaces cannot be mixed in example.php line 8

文字列本体の後に置かれる 終端ID の後に、 セミコロンや改行を続ける必要はありません。 たとえば、次のようなコードが PHP 7.3.0 以降で動作します:

例5 終端ID の後に式を継続する

    <?php
    $values = [<<<END
    a
      b
        c
    END, 'd e f'];
    var_dump($values);

上の例の PHP 7.3 での出力は、このようになります。

    array(2) {
      [0] =>
      string(11) "a
      b
        c"
      [1] =>
      string(5) "d e f"
    }

警告

終端ID が行のはじめに見つかった場合、 それが別の単語の一部かどうかにかかわらず、 それが終端IDと見なされ、 ParseError が起きる可能性があります。

例6 文字列本体に 終端ID が含まれると、ParseError が起きがち

    <?php
    $values = [<<<END
    a
    b
    END ING
    END, 'd e f'];

上の例の PHP 7.3 での出力は、このようになります。

    Parse error: syntax error, unexpected identifier "ING", expecting "]" in example.php on line 5

この問題を避けるために、 次のようなシンプルなルールに従っておくと安全です: 文字列本体に出現するテキストを、終端ID として採用しない

警告

PHP 7.3.0 より前のバージョンで注意すべき非常に重要な点は、 終端ID がある行には、セミコロン (`;`) 以外の他の文字が含まれていてはいけなかったことです。 これは、特に ID はインデントしてはならないということ、 セミコロンの前に空白やタブを付けてはいけないことを意味していました。 終端ID の前の最初の文字は、使用するオペレーティングシステムで定義された 改行である必要があることにも注意を要します。 これは、UNIX システムでは macOS を含め `\n` となります。 最後の区切り文字の後にもまた、改行を入れる必要があります。

この規則が破られて 終端ID が "clean" でない場合、 終端ID と認識されず、PHP はさらに終端 ID を探し続けます。 適当な 終端ID がみつからない場合、 スクリプトの最終行でパースエラーが発生します。

例7 PHP 7.3.0 より前のバージョンでの間違った例

    <?php
    class foo {
        public $bar = <<<EOT
    bar
        EOT;
    }
    // 識別子はインデントしてはいけません
    ?>

例8 PHP 7.3.0 より前のバージョンでも有効な例

    <?php
    class foo {
        public $bar = <<<EOT
    bar
    EOT;
    }
    ?>

変数を含んでいるヒアドキュメントは、クラスのプロパティの初期化に用いることはできません。

ヒアドキュメントは二重引用符を使用しませんが、 二重引用符で括られた文字列と全く同様に動作します。 これはつまり、引用符をエスケープする必要はないが、 上記のリストにあるエスケープされたコードは同様に使用できるということです。 変数は展開されますが、文字列の場合と同様に ヒアドキュメントの内部で複雑な変数を表わす場合には注意が必要です。

例9 ヒアドキュメントで文字列を括る例

    <?php
    $str = <<<EOD
    Example of string
    spanning multiple lines
    using heredoc syntax.
    EOD;

    /* 変数を使用するより複雑な例 */
    class foo
    {
        var $foo;
        var $bar;

        function __construct()
        {
            $this->foo = 'Foo';
            $this->bar = array('Bar1', 'Bar2', 'Bar3');
        }
    }

    $foo = new foo();
    $name = 'MyName';

    echo <<<EOT
    My name is "$name". I am printing some $foo->foo.
    Now, I am printing some {$foo->bar[1]}.
    This should print a capital 'A': \x41
    EOT;
    ?>

上の例の出力は以下となります。

    My name is "MyName". I am printing some Foo.
    Now, I am printing some Bar2.
    This should print a capital 'A': A

ヒアドキュメント構文を用いて、 関数の引数にデータを渡すこともできます。

例10 ヒアドキュメントを引数に使用する例

    <?php
    var_dump(array(<<<EOD
    foobar!
    EOD
    ));
    ?>

static変数やクラスのプロパティ/定数は、 ヒアドキュメント構文で初期化することができます。

例11 ヒアドキュメントを用いた静的な値の初期化

    <?php
    // static 変数
    function foo()
    {
        static $bar = <<<LABEL
    Nothing in here...
    LABEL;
    }

    // クラスのプロパティ/定数
    class foo
    {
        const BAR = <<<FOOBAR
    Constant example
    FOOBAR;

        public $baz = <<<FOOBAR
    Property example
    FOOBAR;
    }
    ?>

ヒアドキュメントの宣言をダブルクォートで囲むこともできます。

例12 ヒアドキュメントでのダブルクォート

    <?php
    echo <<<"FOOBAR"
    Hello World!
    FOOBAR;
    ?>

#### Nowdoc

Nowdoc はヒアドキュメントと似ていますが、 ヒアドキュメントがダブルクォートで囲んだ文字列として扱われるのに対して、 Nowdoc はシングルクォートで囲んだ文字列として扱われます。 Nowdoc の使用方法はヒアドキュメントとほぼ同じですが、 その中身について 文字列の補間処理を行いません。 PHP のコードや大量のテキストを埋め込む際に、 エスケープが不要になるので便利です。この機能は、SGML の `<![CDATA[ ]]>` (ブロック内のテキストをパースしないことを宣言する) と同じようなものです。

Nowdoc の書き方は、ヒアドキュメントと同じように `<<<` を使用します。 しかし、その後に続く識別子をシングルクォートで囲んで `<<<'EOT'` のようにします。 ヒアドキュメントの識別子に関する決まりがすべて Nowdoc の識別子にも当てはまります。特に 終端ID の書き方に関する決まりに注意しましょう。

例13 Nowdoc による文字列のクォートの例

    <?php
    echo <<<'EOD'
    Example of string spanning multiple lines
    using nowdoc syntax. Backslashes are always treated literally,
    e.g. \\ and \'.
    EOD;

上の例の出力は以下となります。

    Example of string spanning multiple lines
    using nowdoc syntax. Backslashes are always treated literally,
    e.g. \\ and \'.

例14 変数がある場合の、Nowdoc による文字列のクォートの例

    <?php
    /* 変数を使った、より複雑な例 */
    class foo
    {
        public $foo;
        public $bar;

        function __construct()
        {
            $this->foo = 'Foo';
            $this->bar = array('Bar1', 'Bar2', 'Bar3');
        }
    }

    $foo = new foo();
    $name = 'MyName';

    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;
    ?>

上の例の出力は以下となります。

    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

例15 静的なデータの例

    <?php
    class foo {
        public $bar = <<<'EOT'
    bar
    EOT;
    }
    ?>

#### 文字列の補間処理

文字列が二重引用符で括られるかヒアドキュメントで指定された場合、 その中の変数は置き換えられます。

構文の型には、単純な構文と 高度な 構文の 2 種類があります。単純な構文は、最も一般的で便利です。 この構文では、変数や配列の値、オブジェクトのプロパティを、 簡単に文字列に埋め込むことができます。

##### 単純な構文

ドル記号 (`$`) を見付けると、 その後に変数名で使える文字は変数として解釈され、置き換えられます。

例16 文字列の置き換え

    <?php
    $juice = "apple";

    echo "He drank some $juice juice." . PHP_EOL;

    ?>

上の例の出力は以下となります。

    He drank some apple juice.

形式的には、文字列の変数の置き換えの文法は下記のようになります:

    string-variable::
         variable-name   (offset-or-property)?
       | ${   expression   }

    offset-or-property::
         offset-in-string
       | property-in-string

    offset-in-string::
         [   name   ]
       | [   variable-name   ]
       | [   integer-literal   ]

    property-in-string::
         ->  name

    variable-name::
         $   name

    name::
         [a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*

警告

`${ expression }` の形式は、 PHP 8.2.0 以降では推奨されなくなりました。 なぜなら、これは 可変変数: として解釈される可能性があるからです。

    <?php
    const foo = 'bar';
    $foo = 'foo';
    $bar = 'bar';
    var_dump("${foo}");
    var_dump("${(foo)}");
    ?>

上の例の PHP 8.2 での出力は、このようになります。:

    Deprecated: Using ${var} in strings is deprecated, use {$var} instead in file on line 6

    Deprecated: Using ${expr} (variable variables) in strings is deprecated, use {${expr}} instead in file on line 9
    string(3) "foo"
    string(3) "bar"

上の例の出力は以下となります。

    string(3) "foo"
    string(3) "bar"

高度な 文字列補間の記法を代わりに使うべきです。

> 注意: 有効な変数名にならない場合、ドル記号は文字列中でそのまま解釈されます:

>     <?php
>     echo "No interpolation $  has happened\n";
>     echo "No interpolation $\n has happened\n";
>     echo "No interpolation $2 has happened\n";
>     ?>

> 上の例の出力は以下となります。

>     No interpolation $  has happened
>     No interpolation $
>      has happened
>     No interpolation $2 has happened

例17 配列の最初の次元やプロパティの値を補間させる

    <?php
    $juices = array("apple", "orange", "string_key" => "purple");

    echo "He drank some $juices[0] juice.";
    echo PHP_EOL;
    echo "He drank some $juices[1] juice.";
    echo PHP_EOL;
    echo "He drank some $juices[string_key] juice.";
    echo PHP_EOL;

    class A {
        public $s = "string";
    }

    $o = new A();

    echo "Object value: $o->s.";
    ?>

上の例の出力は以下となります。

    He drank some apple juice.
    He drank some orange juice.
    He drank some purple juice.
    Object value: string.

> 注意: 配列のキーについては、クォートを外さなければなりません。 よって、単純な記法では定数をキーとして参照できません。 高度な 記法を使ってください。

PHP 7.1.0 以降では、負の 数値インデックスもサポートされています

例18 負の数値インデックス

    <?php
    $string = 'string';
    echo "The character at index -2 is $string[-2].", PHP_EOL;
    $string[-3] = 'o';
    echo "Changing the character at index -3 to o gives $string.", PHP_EOL;
    ?>

上の例の出力は以下となります。

    The character at index -2 is n.
    Changing the character at index -3 to o gives strong.

さらに複雑な処理は、 高度な 記法を使う必要があります。

##### 高度な (波括弧) 記法

高度な波括弧を使った記法を使うと、 任意のアクセス方法で 変数 の補間を行うことができます。

任意のスカラー変数や、配列の要素、オブジェクトのプロパティ (static かそうでないかは問いません) の文字列表現を、この記法に含めることができます。 式は文字列の外部に現れるものと同じやり方で書くことができ、 `{` と `}` で囲みます。 `{` はエスケープできないので、 この記法は `{` のすぐ後に `$` が続く場合にのみ認識されます。 `{$` を使いたい場合は `{\$` と書くようにしてください。 以下の複数の例を見ると、わかりやすいでしょう:

例19 {} による記法

    <?php
    const DATA_KEY = 'const-key';
    $great = 'fantastic';
    $arr = [
        '1',
        '2',
        '3',
        [41, 42, 43],
        'key' => 'Indexed value',
        'const-key' => 'Key with minus sign',
        'foo' => ['foo1', 'foo2', 'foo3']
    ];

    // 動作しない。出力: This is { fantastic}
    echo "This is { $great}" . PHP_EOL;

    // 動作する。出力: This is fantastic
    echo "This is {$great}" . PHP_EOL;

    // 波括弧を出力に含めるには:
    echo "This is {{$great}}" . PHP_EOL;

    class Square {
        public $width;

        public function __construct(int $width) { $this->width = $width; }
    }

    $square = new Square(5);

    // 動作する
    echo "This square is {$square->width}00 centimeters wide." . PHP_EOL;

    // 動作する。クォートされたキーは波括弧構文でのみ動作する
    echo "This works: {$arr['key']}" . PHP_EOL;

    // 動作する
    echo "This works: {$arr[3][2]}" . PHP_EOL;

    echo "This works: {$arr[DATA_KEY]}" . PHP_EOL;

    // 多次元配列を使う場合、文字列内では常に配列を波括弧で囲む
    echo "This works: {$arr['foo'][2]}" . PHP_EOL;

    echo "This works: {$obj->values[3]->name}" . PHP_EOL;

    echo "This works: {$obj->$staticProp}" . PHP_EOL;

    // 動作しない。出力: C:\directory\{fantastic}.txt
    echo "C:\directory\{$great}.txt" . PHP_EOL;

    // 動作する。出力: C:\directory\fantastic.txt
    echo "C:\\directory\\{$great}.txt" . PHP_EOL;
    ?>

> 注意: この記法を使うと任意の式が使えるので、 可変変数 を使うこともできます。

#### 文字列への文字単位のアクセスと修正

$str[42] のように、 角括弧を使用してゼロから始まるオフセットを指定すると、 文字列内の任意の文字にアクセスし、修正することが可能です。 つまり、文字列を文字の配列として考えるわけです。 複数の文字を取り出したり変更したりしたいときは、関数 substr() および substr_replace() が使えます。

> 注意: PHP 7.1.0 以降では、負の文字列オフセットにも対応するようになりました。 これは、文字列の末尾からのオフセットを表します。 以前のバージョンでは、負のオフセットで読み込もうとすると `E_NOTICE` が発生し (空文字列を返します)、負のオフセットで書き込もうとすると `E_WARNING` が発生していました (文字列には何も手が加えられません)。

> 注意: PHP 8.0.0 より前のバージョンでは、 $str{42} のように波括弧を使用してアクセスすることもできました。 この文法は PHP 7.4.0 以降は非推奨になり、 PHP 8.0.0 以降はサポートされなくなっています。

警告

範囲外のオフセットに書き込んだ場合は、その地点まで空白文字で埋められます。 整数型以外の型は整数型に変換されます。 無効なオフセット形式を指定した場合は `E_WARNING` を発行します。 文字列を代入した場合は最初の文字だけを使用します。 PHP 7.1.0 以降では、空の文字列を代入すると 致命的なエラーが発生するようになりました。 これまでのバージョンでは、NULL バイトが代入されていました。

警告

内部的には、PHP の文字列はバイト配列です。 そのため、角括弧を使った配列形式での文字列へのアクセスは、 マルチバイト対応ではありません。この方法は、 ISO-8859-1 のようなシングルバイトエンコーディングの文字列に対してだけしか使えません。

> 注意: PHP 7.1.0 以降では、空の文字列に空のインデックス演算子を適用すると 致命的なエラーが発生するようになりました。 これまでのバージョンではエラーにならず、空の文字列が配列に変換されていました。

例20 文字列の例

    <?php
    // 文字列の最初の文字を取得します
    $str = 'This is a test.';
    $first = $str[0];
    var_dump($first);

    // 文字列の 3 番目の文字を取得します
    $third = $str[2];
    var_dump($third);

    // 文字列の最後の文字を取得します
    $str = 'This is still a test.';
    $last = $str[strlen($str)-1];
    var_dump($last);

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

文字列のオフセットは整数あるいは整数と見なせる文字列に限られます。 それ以外の場合は警告が発生します。

例21 不正な文字列のオフセットの例

    <?php
    $str = 'abc';

    $keys = [ '1', '1.0', 'x', '1x' ];

    foreach ($keys as $keyToTry) {
        var_dump(isset($str[$keyToTry]));

        try {
            var_dump($str[$keyToTry]);
        } catch (TypeError $e) {
            echo $e->getMessage(), PHP_EOL;
        }

        echo PHP_EOL;
    }
    ?>

上の例の出力は以下となります。

    bool(true)
    string(1) "b"

    bool(false)
    Cannot access offset of type string on string

    bool(false)
    Cannot access offset of type string on string

    bool(false)

    Warning: Illegal string offset "1x" in Standard input code on line 10
    string(1) "b"

> 注意:

> その他の型の変数 (配列や、適切なインターフェイスを実装したオブジェクトを除く) に対して `[]` や `{}` でアクセスすると、何もメッセージを出さずに単に `null` を返します。

> 注意:

> 文字列リテラル内の文字に対して `[]` や `{}` でアクセスすることができます。

> 注意:

> 文字列リテラル内の文字に対して、 `{}` を使ってアクセスする機能は、 PHP 7.4 で非推奨になり、PHP 8.0 で削除されました。

### 便利な関数および演算子

文字列は、'.' (ドット) 結合演算子で結合することが可能です。'+' (加算) 演算子はこの例では出てこないことに注意してください。詳細については 文字列演算子 を参照ください。

文字列の修正を行う場合には、便利な関数がたくさん用意されています。

一般的な関数については、文字列関数の節 を参照ください。高度な検索/置換を行う関数については Perl 互換の正規表現関数 を参照ください。

URL 文字列用関数や文字列の暗号化/ 復号用の関数 (Sodium および Hash) もあります。

最後に、探しているものがまだ見付からない場合には、 文字型の関数も参照ください。

### 文字列への変換

`(string)` キャストや strval() 関数を使って変数を文字列へ変換することができます。 文字列型を必要とする式のスコープにおいて、文字列への変換は自動的に行われます。 echo や print 関数を使うとき、 あるいは変数を文字列と比較するときにこの自動変換が行われます。 マニュアルの型 と 型の相互変換 の項を読むとわかりやすいでしょう。 settype()も参照ください。

bool の `true` は文字列の `"1"` に、 `false` は `""` (空文字列) に変換されます。 これにより boolean と文字列の値を相互に変換することができます。

int (整数) や浮動小数点数 (float) は その数値の数字として文字列に変換されます (指数の表記や浮動小数点数を含めて)。 浮動小数点数は、指数表記 (`4.1E+6`) を使用して変換されます。

> 注意:

> PHP 8.0.0 以降では、小数点を表す文字は常にピリオド ("`.`") です。 それより前のバージョンでは、 スクリプトのロケール (LC_NUMERIC カテゴリ) によって決まります。 setlocale() を参照ください。

配列は常に `"Array"` という文字列に変換されるので、 array の中を見るために echo や print を使ってダンプさせることはできません。 一つの要素を見るためには、`echo $arr['foo']` のようにしてください。内容の全てをダンプ/見るためには以降の TIP をご覧ください。

object を string へ変換するには、 マジック・メソッド __toString を使用してください。

リソースは常に `"Resource id #1"` という文字列に変換されます。`1` は実行中の PHP によって割り当てられる resource の番号です。 この文字列の構造に依存したコードを書いてはいけません (この構造は変わる可能性があります) が、スクリプトの実行中 (ウェブのリクエストや CLI プロセスの処理中) は、指定したリソースに対してこの文字列が一意に割り当てられることが保証されます。 他のリソースで同じ文字列が再利用されることはありません。 リソースの型を知るためには get_resource_type() を使用してください。

`null` は常に空文字列に変換されます。

以上に述べたように、配列、オブジェクト、リソースをプリントアウトしても その値に関する有益な情報を得られるわけではありません。 デバッグのために値を出力するのによりよい方法が知りたければ、 print_r() や var_dump() を参照ください。

PHP 変数を恒久的に保存するための文字列に変換することもできます。 この方法はシリアライゼーションと呼ばれ、 serialize() 関数によって実現できます。

### 文字列型の詳細

PHP における文字列型は、バイトの配列と整数値 (バッファ長) で実装されています。 バイト列を文字列に変換する方法については何の情報も持っておらず、完全にプログラマ任せとなっています。 文字列を構成する値には何の制限もありません。特に気をつけるべきなのは、 値 `0` のバイト (いわゆる “NUL バイト”) を文字列内のどの部分にでも使えるという点です (しかし、このマニュアル上で「バイナリセーフではない」とされている一部の関数では、 受け取った文字列をライブラリに渡すときに NUL バイト以降を無視することがあります)。

PHP の文字列型の正体を知ってしまえば、なぜ PHP には「バイト型」が存在しないのかもわかります。 つまり、文字列型がその役割を受け持っているのです。テキスト以外のデータ、 たとえばネットワークソケットから読み込んだ任意のデータを返す関数も、 文字列で値を返します。

PHP が文字列に対して特定のエンコーディングを強制しないのなら、 いったいどのようにして文字列リテラルをエンコードしているのでしょう? たとえば、文字列 `"á"` と同等なのは `"\xE1"` (ISO-8859-1)、 `"\xC3\xA1"` (UTF-8, C form)、 `"\x61\xCC\x81"` (UTF-8, D form) のどれでしょう? あるいはそれ以外の何かなのでしょうか? 実は、文字列のエンコードはスクリプトファイルのエンコード方式に従って行われるというのが正解です。 したがって、もしスクリプトが ISO-8859-1 で書かれているのなら、文字列も ISO-8859-1 でエンコードされます。その他のエンコードの場合も同様です。 しかし、Zend Multibyte が有効になっている場合は話が別です。 この場合は、スクリプトはどんなエンコーディングで書いてもかまいません (明示的に宣言することもできるし、自動検出させることもできます)。 スクリプトはその後で内部エンコーディングに変換されるので、 文字列リテラルも内部エンコーディングと同じ方式で符号化されます。 スクリプトのエンコーディング (あるいは、Zend Multibyte を有効にした場合の内部エンコーディング) には、一部制限があることに注意しましょう。 ひとことで言うと、ASCII の上位互換 でなければならないということです。 UTF-8 や ISO-8859-1 などがこれにあたります。 しかし、状態に依存する (たとえば、同じバイト値が、先頭にあるときとシフト状態にあるときで違う意味になる) エンコーディングは、問題になる可能性があります。

もちろん、利便性を考慮すれば、テキストを操作する関数が文字列のエンコードを扱う際に 何らかの前提に基づかざるを得ないこともあります。 残念ながら、PHP の各関数が文字列のエンコーディングを判断する方法はまったく統一されていません。

- いくつかの関数は、文字列が何らかのシングルバイトエンコーディングで符号化されているものと見なします。 しかし、文字列内の各バイトが必ずしも特定の文字に変換できなくてもかまいません。 このタイプの関数は、substr() や strpos()、strlen()、 strcmp() などです。 これらの関数については、文字列を扱うというよりメモリ上のバッファを扱うものととらえてもよいでしょう。 つまり、バイト列とバイトオフセットで考えるということです。
- 文字列のエンコーディングを受け取る関数もあります。 エンコーディング情報を省略したときにはデフォルトを用意していることもあるでしょう。 このタイプの関数の例は、htmlentities() や 大半の mbstring 関数です。
- 現在のロケール (setlocale() を参照ください) を使うけれども、 処理はバイト単位で行う関数もあります。
- 最後に、文字列が特定のエンコーディング (たいていは UTF-8) であることを前提としている関数があります。 intl の関数や PCRE の関数 (`u` 修飾子を使う場合のみ) の多くがこのタイプになります。

結局、Unicode を使うプログラムをきちんと書くには、 うまく動かない関数を使わないよう注意するしかないということです。 特にデータを破壊してしまう可能性のある関数の使用は避け、 きちんと動作する関数を使うようにしましょう。 intl や mbstring の関数を選択するとよいでしょう。 しかし、Unicode をまともに扱える関数を使うというのは単なる始まりに過ぎません。 たとえ関数側で Unicode を扱う機能があったとしても、 Unicode の仕様に関する知識は不可欠です。 たとえば、世の中には大文字と小文字しか存在しないという思い込みで作ったプログラムは、 うまく動かない可能性があります。

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open