01-看官方文档学PHP基础-String

  • string 最大可以达到 2GB

1. 单引号

永远保留字符串原味

不像双引号和 heredoc 语法结构,在单引号字符串中的变量和特殊字符的转义序列将不会被替换。

2. 双引号

如果字符串是包围在双引号(”)中, PHP 将对一些特殊的字符进行解析:

正例:

echo "This will not expand: \n a newline"; //这个可以换行

3. Heredoc 结构

Heredoc 结构就象是没有使用双引号的双引号字符串

正例:

<?php
echo <<<DOC
这里随便写
ASDFASDFASDF
任意随机字符串
可以用lorem加tab键自动填充
ASDFASDFASDF
DOC;

注意

例子中的标识符是DOC,以<<<DOC开始,以DOC;结束.

  1. 结束时,DOC是顶头的,前面 没有 任何空格!!必须这样做!!
  2. 结束标识符这行除了 可能 有一个分号;外,绝对不能包含其它字符。这意味着标识符不能缩进,分号的前后也不能有任何空白或制表符。
  3. 更重要的是结束标识符的前面必须是个被本地操作系统认可的换行,比如在 UNIX 和 Mac OS X 系统中是 \n,而结束定界符(可能其后有个分号)之后也必须紧跟一个换行。
  4. 如果结束标识不“干净”,PHP 将继续寻找结束标识。如果在文件结束前也没有找到,PHP 将会在最后一行产生一个解析错误。
  5. Heredocs 结构不能用来初始化类的属性。自 PHP 5.3 起,此限制仅对 heredoc 包含变量时有效。
  6. 结束需要特别注意,尤其是;,建议看看文末的User Contributed Notes,转自PHP官方.

更复杂的例子:

/* 含有变量的更复杂示例 */
class foo
{
var $foo;
var $bar;

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

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

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 "BHL". I am printing some Foo.
Now, I am printing some Bar2.
This should print a capital 'A': A

也可以把 Heredoc 结构用在函数参数中来传递数据:

Example #3 Heredoc 结构在参数中的示例

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

输出:

array(1) {
[0]=>
string(7) "foobar!"
}

在 PHP 5.3.0 以后,也可以用 Heredoc 结构来初始化静态变量和类的属性和常量:

正例:

<?php
// 静态变量
function foo()
{
static $bar = <<<LABEL
Nothing in here...
LABEL;
}

// 类的常量、属性
class foo
{
const BAR = <<<FOOBAR
Constant example
FOOBAR;

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

自 PHP 5.3.0 起还可以在 Heredoc 结构中用双引号来声明标识符:

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

4. Nowdoc 结构

Nowdoc 结构是在 PHP 5.3.0 中加入的。

Nowdoc 结构是类似于单引号字符串

  1. nowdoc 中不进行解析操作
  2. 这种结构很适合用于嵌入 PHP 代码或其它大段文本而无需对其中的特殊字符进行转义。
  3. 与 SGML 的 <![CDATA[ ]]> 结构是用来声明大段的不用解析的文本类似,nowdoc 结构也有相同的特征。
  4. nowdoc 结构也用标记 <<<, 但是跟在后面的标识符要用单引号括起来,即 <<<'EOT'
  5. Heredoc 结构的所有规则也同样适用于 nowdoc 结构,尤其是结束标识符的规则。

Example #6 Nowdoc 结构字符串示例

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

/* 含有变量的更复杂的示例 */
class foo
{
public $foo;
public $bar;

function foo()
{
$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

nowdoc 结构可以用在任意的静态数据环境中,最典型的示例是用来初始化类的属性或常量:

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

变量解析

  1. 简单规则: 最常用和最方便,用最少的代码在一个 string 中嵌入一个变量,一个 array 的值,或一个 object 的属性。
  2. 复杂规则: 是用花括号包围的表达式。

1. 简单语法

当 PHP 解析器遇到一个美元符号($)时,它会和其它很多解析器一样,去组合尽量多的标识以形成一个合法的变量名。可以用花括号来明确变量名的界线。

<?php
$juice = "apple";
//PHP_EOL是换行的意思
echo "He drank some $juice juice.".PHP_EOL;
// Invalid. "s" is a valid character for a variable name, but the variable is $juice.
echo "He drank some juice made of $juices.";
?>

输出:

He drank some apple juice.
He drank some juice made of .

Example #8 简单语法示例

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

echo "He drank some $juices[0] juice.".PHP_EOL;
echo "He drank some $juices[1] juice.".PHP_EOL;
echo "He drank some juice made of $juice[0]s.".PHP_EOL; // Won't work,juice少了个s,报错!
echo "He drank some $juices[koolaid1] juice.".PHP_EOL;

class people {
public $john = "John Smith";
public $jane = "Jane Smith";
public $robert = "Robert Paulsen";

public $smith = "Smith";
}

$people = new people();

echo "$people->john drank some $juices[0] juice.".PHP_EOL;
echo "$people->john then said hello to $people->jane.".PHP_EOL;
echo "$people->john's wife greeted $people->robert.".PHP_EOL;
echo "$people->robert greeted the two $people->smiths."; // Won't work,smiths多了个s
?>

输出:

He drank some apple juice.
He drank some orange juice.
Notice: Undefined variable: juice in /vagrant/code/default/base/example_8.php on line 6
He drank some juice made of s.
He drank some purple juice.
John Smith drank some apple juice.
John Smith then said hello to Jane Smith.
John Smith's wife greeted Robert Paulsen.
Notice: Undefined property: people::$smiths in /vagrant/code/default/base/example_8.php on line 22
Robert Paulsen greeted the two .

2. 复杂(花括号)语法

复杂语法不是因为其语法复杂而得名,而是因为它可以使用复杂的表达式。

  • 只有 $ 紧挨着 { 时才会被识别

  • 只有花括号语法能正确解析带引号的键名,如:{$arr['key']}可以被正确的解析,{$arr[4][3]}是有效的,
    需要注意,{$arr['key']}的”key”是有引号的,不加引号常常会报错,除非你能让php找到名为key的常量

    <?php
    // 显示所有错误
    error_reporting(E_ALL);

    $great = 'fantastic';

    // 无效,输出: This is { fantastic}
    echo "This is { $great}";

    // 有效,输出: This is fantastic
    echo "This is {$great}";
    echo "This is ${great}";

    // 有效
    echo "This square is {$square->width}00 centimeters broad.";

    // 有效,只有通过花括号语法才能正确解析带引号的键名
    echo "This works: {$arr['key']}";

    // 有效
    echo "This works: {$arr[4][3]}";

    // 这是错误的表达式,因为就象 $foo[bar] 的格式在字符串以外也是错的一样。
    // 换句话说,只有在 PHP 能找到常量 foo 的前提下才会正常工作;这里会产生一个
    // E_NOTICE (undefined constant) 级别的错误。
    echo "This is wrong: {$arr[foo][3]}";

    // 有效,当在字符串中使用多重数组时,一定要用括号将它括起来
    echo "This works: {$arr['foo'][3]}";

    // 有效
    echo "This works: " . $arr['foo'][3];

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

    echo "This is the value of the var named $name: {${$name}}";

    echo "This is the value of the var named by the return value of getName(): {${getName()}}";

    echo "This is the value of the var named by the return value of \$object->getName(): {${$object->getName()}}";

    // 无效,输出: This is the return value of getName(): {getName()}
    echo "This is the return value of getName(): {getName()}";
    ?>
  • 通过变量来调用类的属性,调用foo方法里的变量$bar$foo->bar,如何通过变量来调用bar这个属性呢:

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

$foo = new foo();
$bar = 'bar'; //这句就意味着后面的{$foo->$bar}实质上是{$foo->bar}
//这句以为着,后面的{$foo->$bar}可能调用的是{$foo->bar}或{$foo->foo}或{$foo->baz}等,由$baz[i]数组的i确定调用的是哪个.
$baz = array('foo', 'bar', 'baz', 'quux');
echo "{$foo->$bar}\n"; // 输出I am bar.
echo "{$foo->$baz[1]}\n"; // 输出I am bar.如果是$baz[2]则输出I am baz.
?>
  • 函数、方法、静态类变量和类常量只有在 PHP 5 以后才可在 {$} 中使用。注意看注释:
<?php
// 显示所有错误
error_reporting(E_ALL);

class beers {
const softdrink = 'rootbeer'; // $rootbeer 在下面被定义了,所以该值在调用的时候可以直接作为变量名用$调用,输出为`A & W`
public static $ale = 'ipa';
}

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

// 有效,输出: I'd like an A & W
echo "I'd like an {${beers::softdrink}}\n";

// 也有效,输出: I'd like an Alexander Keith's
echo "I'd like an {${beers::$ale}}\n";
?>

这是官方简体中文文档:
函数、方法、静态类变量和类常量只有在 PHP 5 以后才可在 {$} 中使用。然而,只有在该字符串被定义的命名空间中才可以将其值作为变量名来访问。只单一使用花括号 ({}) 无法处理从函数或方法的返回值或者类常量以及类静态变量的值。

实在是读不懂,下面是英文原文:

Functions, method calls, static class variables, and class constants inside {$} work since PHP 5. However, the value accessed will be interpreted as the name of a variable in the scope in which the string is defined. Using single curly braces ({}) will not work for accessing the return values of functions or methods or the values of class constants or static class variables.

看是英文看的更明白些,意思就是,什么函数啊,方法调用啊静态变量和类属性等等的,从PHP5开始可以用{$}的方式调用,他们的值可以被解析成变量名使用,(看例子)前提是,这些变量名在可调用的地方被定义了.单纯的用{}无法调用方法,类属性等的返回值

存取和修改字符串中的字符

String access and modification by character

  • string可以理解为是一个字符数组,下标从0开始,str[42]str{42}都可以访问和修改string中的字符;
  • 要写入字符下标的位置超出字符串长度则会拉长字符串,被拉长部分用空格填充;
  • 非整数类型下标会被转换成整数
  • 非法下标类型,用负数做下标都会产生E_NOTICE级别错误
  • 负数下标读取字符串读取到的是空字符串(Negative offset emits E_NOTICE in write but reads empty string)
  • 写入时只用到了赋值字符串的第一个字符(Only the first character of an assigned string is used)
  • 用空字符串赋值则赋给的值是 NULL 字符( Assigning empty string assigns NULL byte)
  • 自 PHP 5.4 起字符串下标必须为整数或可转换为整数的字符串,否则会弹出警告,例如,这些写法,虽然输出结果和PHP5.4以前一样,但是PHP5.4开始会告警:$str['1.0']会被转换成$str[1]$str['1x']会被转换成$str[1]$str['x']会被转换成$str[0]
  • 用[]或{}访问其他类型(除了数组或实现相应接口的对象)变量时会默默的返回NULL
  • PHP 5.5 开始,支持用[]或{}直接访问字符串里的字符
    Example #9 一些字符串示例
<?php
// 取得字符串的第一个字符
$str = 'This is a test.';
$first = $str[0]; //is T

// 取得字符串的第三个字符
$third = $str[2]; //is i

// 取得字符串的最后一个字符
$str = 'This is still a test.';
$last = $str[strlen($str)-1]; //is .

// 修改字符串的最后一个字符
$str = 'Look at the sea';
$str[strlen($str)-1] = 'e'; //sea => see
?>

有用的函数和运算符

Useful functions and operators

转换成字符串

Converting to string

  • 前面加(string)或用strval()可以转换目标为字符串,在需要的时候,他们可以自动转换成字符串.比如echo ,print, 和string 对象比较的时候
  • boolean的true被转换成”1”,false被转换成””,这些转换在boolean和string之间可以相互转换.
  • array数组总是会被转换成Array,obejct对象总是被转换成Object ,资源resource总是被转换成Resource id #1,1有可能是运行时分配给resource的唯一值.
  • 要得到object的类型名称用get_class(),PHP5起,在类内部写__toString()魔术方法,方法里面写打印类名,从而实现echo和print直接输出类名,而不是Object.要得到resource的类型,可以用get_resource_type()方法.
  • 要得到这些对象内的数据信息,可以用print_r()var_dump(),在 laravel 中更建议使用 dd()的方法来显示对象或资源内部的数据信息.
  • 大部分的PHP值可以转变成string来永久保存,被称为串行化,可以用serialize()实现
  • 如果PHP引擎被设定支持 WDDX PHP值也可以被串行化为格式良好的XML文本.

字符串转换为数值

String conversion to numbers

当一个字符串被放在数字序列中当做数字看待的时候,它的值应该是这样的:

  • 如果字符串不包含任何.eE,并且数字的值在整型范围(由PHP_INT_MAX所定义)之内,该字符串将会被当成整型来取值,其他所有情况被当做float来取值.
  • 字符串的开始决定了它的值,如果以合法数值开始则使用该数值,否则该值为0.

例子:

<?php
$foo = 1 + "10.5"; // $foo is float (11.5)
$foo = 1 + "-1.3e3"; // $foo is float (-1299) -1.3 * 10e3
$foo = 1 + "bob-1.3e3"; // $foo is integer (1)
$foo = 1 + "bob3"; // $foo is integer (1)
$foo = 1 + "10 Small Pigs"; // $foo is integer (11)
$foo = 4 + "10.2 Little Piggies"; // $foo is float (14.2)
$foo = "10.0 pigs " + 1; // $foo is float (11)
$foo = "10.0 pigs " + 1.0; // $foo is float (11)
?>

测试上面的例子:

<?php
echo "\$foo==$foo; type is " . gettype ($foo) . "<br />\n";
?>

字符串类型详解 - 最后这段是最没搞懂的

Details of the String Type

  • PHP 中没有单独的”byte”类型 - 已经用字符串来代替了

  • 非文本值返回值的函数仍然会返回字符串 - 从网络套接字读取的任意数据,以字符串的方式返回

  • 由于 PHP 并不特别指明字符串的编码,字符串会被按照该脚本文件相同的编码方式来编码。

  • 激活了 Zend Multibyte 时,脚本可以是以任何方式编码的(明确指定或被自动检测)然后被转换为某种内部编码,然后字符串将被用此方式编码。

  • 注意脚本的编码有一些约束(如果激活了 Zend Multibyte 则是其内部编码)- 这意味着此编码应该是 ASCII 的兼容超集,例如 UTF-8 或 ISO-8859-1。

  • 注意,依赖状态的编码其中相同的字节值可以用于首字母和非首字母而转换状态,这可能会造成问题。

  • 操作文本的函数必须假定字符串是如何编码的。不幸的是,PHP 关于此的函数有很多变种:

    • 某些函数假定字符串是以单字节编码的,但并不需要将字节解释为特定的字符。例如 substr(),strpos(),strlen() 和 strcmp()。理解这些函数的另一种方法是它们作用于内存缓冲区,即按照字节和字节下标操作。
    • 某些函数被传递入了字符串的编码方式,也可能会假定默认无此信息。例如 htmlentities() 和 mbstring 扩展中的大部分函数。
    • 其它函数使用了当前区域(见 setlocale()),但是逐字节操作。例如 strcasecmp(),strtoupper() 和 ucfirst()。这意味着这些函数只能用于单字节编码,而且编码要与区域匹配。例如 strtoupper(“á”) 在区域设定正确并且 á - - 是单字节编码时会返回 “á”。如果是用 UTF-8 编码则不会返回正确结果,其结果根据当前区域有可能返回损坏的值。
    • 最后一些函数会假定字符串是使用某特定编码的,通常是 UTF-8。intl 扩展和 PCRE(上例中仅在使用了 u 修饰符时)扩展中的大部分函数都是这样。尽管这是由于其特殊用途,utf8_decode() 会假定 UTF-8 编码而 utf8_encode() 会假定 ISO-8859-1 编码。

最后,要书写能够正确使用 Unicode 的程序依赖于很小心地避免那些可能会损坏数据的函数。要使用来自于 intl 和 mbstring 扩展的函数。不过使用能处理 Unicode 编码的函数只是个开始。不管用何种语言提供的函数,最基本的还是了解 Unicode 规格。例如一个程序如果假定只有大写和小写,那可是大错特错。


User Contributed Notes

The documentation does not mention, but a closing semicolon at the end of the heredoc is actually interpreted as a real semicolon, and as such, sometimes leads to syntax errors.

This works:

<?php
$foo = <<<END
abcd
END;
?>

This does not:

<?php
foo(<<<END
abcd
END;
);
// syntax error, unexpected ';'
?>

Without semicolon, it works fine:

<?php
foo(<<<END
abcd
END
);
?>

当两个字符串都可以被转换成数字(numeric)时,他们对应的数字结果会用来被操作,否则会逐个字符的比较整个字符串.
When both strings can be converted to the numerics (in (“$a” > “$b”) test) then resulted numerics are used, else FULL strings are compared char-by-char:

<?php
var_dump('1.22' > '01.23'); // bool(false)
var_dump('1.22.00' > '01.23.00'); // bool(true)
var_dump('1-22-00' > '01-23-00'); // bool(true)
var_dump((float)'1.22.00' > (float)'01.23.00'); // bool(false)
?>
0%