# 字符串

## **字符串的3种定义方式**

* 1、单引号
* 2、双引号
* 3、heredoc 和nowdoc

## 区别

**单引号：**

* 1、单引号不解析变量
* 2、单引号不能解析转移字符，只能解析单引号和反斜线本身
* 3、变量和变量、变量和字符串、字符串和字符串之间可以用.连接

**双引号:**&#x20;

* 1、双引号可以解析**变量**，变量可以使用特殊字符和{ }包含
* 2、双引号可以解析所有转义字符
* 3、也可以使用.来连接

> 双引号到底解析哪些字符?
>
> 1、当字符串用双引号或 heredoc 结构定义时，其中的变量将会被解析。
>
> 2、\n , \r , \t , \v , \e , \f , , $ , \“
>
> 3、\\\[0-7]{1,3} 符合该正则表达式序列的是一个以八进制方式来表达的字符
>
> 4、\x\[0-9A-Fa-f]{1,2} 符合该正则表达式序列的是一个以十六进制方式来表达的字符

**Heredoc :**

* 1、开始标记和结束标记使用相同的字符串，通常以大写字母来写。
* 2、开始标记后不能出现空格或多余的字符。
* 3、结束标记必须顶头写，不能有缩进和空格，且在结束标记末尾要有分号 。
* 4、位于开始标记和结束标记之间的**变量**可以被正常解析，但是函数则不可以。在heredoc中，变量不需要用连接符.或,来拼接 。

**Nowdoc：**

* 1、其用法和heredoc相同，两者都是处理大文本，不同的是Nowdoc 结构是类似于单引号字符串的。
* 2、其语法和单引号字符类似。

**区别：**&#x20;

* 单引号效率更高。
* Heredoc 类似于双引号
* Newdoc 类似于单引号

## 单引号，双引号区别示例

```
echo "this is a pen , \nthis is a pen." .'<br>';
echo 'this is a pen, \nthis is a pen.'.'<br>';

echo "\101\102".'<br>';
echo "\x41\x42".'<br>';

echo  "\\".'<br>';
echo  '\\'.'<br>';
```

结果：

```
this is a pen , this is a pen.
this is a pen, \nthis is a pen.
AB
AB
\
\
```

示例：

```
$a = 'world';
echo 'hello $a \n\'\\';
echo '<br>';
echo "hello '{$a}' '$a' $a \n\'\\";
```

结果：

```
hello $a \n'\
hello 'world' 'world' world &world& \'\
```

1.单引号，只解析了 单引号和反斜线本身，变量和其他转义字符都没有被解析

2.而双引号则全部进行了解析

## 用法

**单引号双引号：**

```
$sql = "select * FROM user WHERE name='$name'";
```

单引号效率更高。并且独立的变量可读性会更高。应该写成：

```
$sql = 'select * FROM user WHERE name=\'' . $name . '\'';
```

**Heredoc 用法:**

```php
<?php

$a = 'world';
echo <<<EOT
   <html>
   <head><title>主页</title></head>
   <body>hello $a</body>
   </html>
EOT;
```

自 PHP 5.3.0 起还可以在 Heredoc 结构中用双引号来声明标识符，所以开头这句也可以写为`echo <<<"EOT"`

**Nowdoc用法**

在 PHP 5.3.0 及其以后的版本中增加了nowdoc结构，其用法和heredoc相同，不同的是Nowdoc 结构是类似于单引号字符串的。nowdoc 中不进行解析操作。这种结构很适合用于嵌入 PHP 代码或其它大段文本而无需对其中的特殊字符进行转义。

一个 nowdoc 结构也用和 heredocs 结构一样的标记`<<<`， 但是跟在后面的标识符要用单引号括起来，即`<<<'EOT'`。

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

> ```
> 在使用heredoc和nowdoc时，经常会遇到如下报错：
> Parse error: syntax error, unexpected T_SL in php
>
> 一段遇到该问题的原因是定界符之后空格的问题引起的。如的EOT后面有空格就会报这个错。
> ```

## 字符串“串行化”

大部分的 PHP 值可以转变成 string 来永久保存，串行化的目的是把一些其他的数据类型，不方便存储的数据类型（比如数组和对象无法直接保存入mysql或者memcache中的）。

* 方法一：函数 serialize() 序列化可以实现
* 方法二：函数 json\_encode ()可以实现，常用
* 方法三：函数 var\_export($items, true);　参数为true,将一个数据返回给变量，并且内容和php语法一致。

> ### **serialize() 与　json\_encode的区别，在于对一个对象的操作**
>
> １.序列化反序列化后仍然是相同的对象
>
> ２．json\_\_encode(),再json\_\_ddecode(),后对象有可能发生变化
>
> 所以如果要存储一个对象并且还需要能够将对象重新实例化的话则需要serialize
>
> 性能方面json\_\_encode() 比 \_serialize()高些，但表现不是很明显
>
> ```php
> class User {
>     function getUserName($name) {
>         echo $name;
>     }
> }
>
>
> $user = new User();
> $serializeUser = serialize($user);
> $unserializeUser = unserialize($serializeUser);
> var_dump($unserializeUser);
> $unserializeUser->getUserName('revin');
>
> $user1 = new User();
> $jsonEncodeUser1 = json_encode($user1);
> $jsonDecodeUser1 = json_decode($jsonEncodeUser1);
> var_dump($jsonDecodeUser1);
> $jsonDecodeUser1->getUserName('revin');
> ```
>
> 结果：
>
> ```
> object(User)[2]
> revin
> object(stdClass)[4]
> atal error: Call to undefined method stdClass::getUserName() in xxx
> ```
>
> 例子很明显。
>
> ### var\_export 用法：
>
> ```php
> $str = [1,2,3,4,5,6];
> $str = var_export($str, true);
> $str = '<?php return ' . $str .';';
> file_put_contents('test.php', $str);
>
>
> $test = include 'test.php';
> var_dump($test);
> ```
>
> 结果：
>
> ```
> array (size=6)
>   0 => int 1
>   1 => int 2
>   2 => int 3
>   3 => int 4
>   4 => int 5
>   5 => int 6
> ```
>
> 开发思路：比如从数据库提取的配置文件，组成数组的形式放入到一个文件中，当下次访问include从文件提取即可,文件缓存方式。

## 其他

**底层C语言中怎么表示PHP字符串？**

```
struct {
    char *val;
    int len;
} str;
```

**字符串的存取**

* 字节组成的数组可以用\[]或者{}访问某个字符(也就是像操作一个数组的方式操作字符串)
* 字符串长度可以达到2G(内存)
* 常见函数都是单字节处理方式
* 可以用\[]或者{}访问某个字符
* PHP字符串是二进制安全的，而在ｃ语言中不是安全的。

> 为什么在ｃ语言中不安全?
>
> C语言中字符串会逐个扫描字符，直到遇见 '\0' 就会结束
>
> 而在中不会因为你加入了\0 就会导致字符串被截断输出。
>
> 更多请看[C语言字符数组和字符串](http://c.biancheng.net/cpp/html/2921.html)

示例:

```php
$str = '123456';
echo $str[1] .'<br>';
echo $str{0} .'<br>';
$str[100] = 'e';
echo ($str) .'<br>';
echo (strlen($str)) .'<br>';
```

结果：

```
2
1
123456 e
101
```

字符串存取总结:

* string 中的字符可以通过一个从 0 开始的下标，用类似 array 结构中的方括号包含对应的数字来访问和修改，比如 $str\[42]。
* 也可用花括号访问，比如 $str{42}。数组可以这么访问么？&#x20;
* 用超出字符串长度的下标写入将会拉长该字符串并以空格填充。
* 非整数类型下标会被转换成整数。非法下标类型会产生一个 E\_NOTICE 级别错误。
