[论学习PHP从开始到放弃]PHP and MySQL web development

[复制链接]

8

主题

135

帖子

3270

积分

超级月卡

Rank: 7Rank: 7Rank: 7

积分
3270
发表于 2020-9-3 16:53:18 | 显示全部楼层 |阅读模式
本帖最后由 why 于 2020-9-10 19:21 编辑

因为看不懂我都有些郁闷了,都说PHP是相对比较简单的,但这书真是前言不搭后语后语,网上翻了一遍,这个译本根本就没法看,太拙劣
新手不建议看这本书,后边已经没法再看了,实在看不懂,都说是一本web开发圣经,但可能说的不是中文版,看书只会让你越看越不懂,放弃这本书,有c语言加持都理解不了书里说的是啥.等以后有经验了再回头来看吧
接下来看这本,买的书还没回来。这本书也买好久了,是网页开发的,当然我也没看过。查了一下有C语言的加持很快就可以浏览一遍了,没书看了就先看这本吧

/*apache,php以及mysql的关系:

apache是web服务器,主要是请求和响应的功能,是一种软件,用于发布网站。在配置文件中可以设置文件根目录,处理的文件类型以及端口等。apache单独不能处理php代码。

php(php 应用程序服务器):不能单独存在的,需要以apache为依托。也可以说php是apache功能模块的一种扩展,php作为apache的外挂,用于解 析php代码。经过解析的动态网页此时就不存在<?php ?>了。当apache服务启动的同时也启动了php。也就是说php必须和apache安装在同一台服务器上,不可以分割。

mysql:一种开源的很流行的关系型数据库。与apache无关,只是在响应php代码中的sql操作的时候才被访问。不需要与apache安装在同一台服务器上,可以单独存在,只需php远程连接即可。2020.09.07*/

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

回复

使用道具 举报

8

主题

135

帖子

3270

积分

超级月卡

Rank: 7Rank: 7Rank: 7

积分
3270
 楼主| 发表于 2020-9-3 23:23:56 | 显示全部楼层
本帖最后由 why 于 2020-9-5 10:40 编辑

第一章 php快速入门教程
1.3.1PHP标记

PHP标记有两种不同的风格可供使用。下面这两段代码是等价的:   xml风格
    <?php echo '<p>order processed.</p>';  ?>
它是PHP推荐使用的标记风格。
  简短风格
    <? echo '<p>order processed.</p>';  ?>  
要使用这种标记风格(输入字符少),必须在配置文件汇总启用short_open_tag选项,或者启用短标记选项编译PHP,不推荐使用这个风格标记,因为这种风格在许多环境的默认设置中是不支持的

1.3.2PHP语句
通过将PHP语句放置在PHP的开始标记和结束标记之间,我们可以告诉PHP解释器进行何种操作,如:
   <?php echo '<p>order processed.</p>';  ?>
echo的作用:将传递给其自己的字符串打印到浏览器
注意,在echo语句的结束处出现一个分号。在PHP中,分号是用来分隔语句的。

1.3.3空格
间隔字符,如换行、空格、和Tab(制表符),都被认为是空格,浏览器会忽略HTML的空格字符,PHP引擎同样会忽略这些空格字符

1.3.4注释
单多好注释可以使用c语言注释格式// 。或者/*……*/

1.4添加动态内容
1.4.1调用函数
date(‘H:i, jS F’)
date()函数希望你传递给它的自动变量时格式化字符串,这个字符串表示所徐勇的输出的输出格式。字符串的每一个自动都表示日期和时间的一部分。H是24小时格式的小时,i是分钟,如果小时数和分钟数是个位数,需要在前面补0,j是该月的日期,不需要在前面补0,而S表示顺序后缀,F是月份的全称

1.5访问表单变量
你可以按如下所示的方法防伪码tireqty域内容:
   $_POST['tireqty']
$_POST是一个数组,包含了通过HTTP POST请求提交的数据,也就是,表单的method属性设置为post。有三个数组可以包含表单数据:$_POST、$_GET、$REQURST。$_POST和$_GET都保存所有表单变量的详细信息。使用那个数组是由提交表单所使用的方法确定的,也就是GET或POST。此外,$_REQURST可以获得get和post提交的数据组合
如果表单是通过post提交的,tirqty文件输入框中的数据将保存在$_POST['tireqty']中。如果表单是通过get方法提交的,数据将保存在$_GET['tireqty']中,在任何一种情况下,数据都可以通过$_REQUEST['tireeqty']获得
这些数组被称作超级全局(superglobal)数组。
赋值操作符“=”
如下代码将创建一个名为$tireqty的新变量,并且将$POST['tireqty']的内容赋值给这个新变量
    $tireqty = $_POST['tireqty'];

1.5.2字符串连接
     echo htmlspecialchars($tireqty).' tireqty<br />';
代码中的“.”是字符串连接符,它可以将几段文本连接成一个字符串。通常,当使用echo命令向浏览器发送输出时,将使用这个连接符。这样可以避免编写多个echo命令
也可以将简单的变量写入一个由双引号引用的字符串中。如:
    $tireqty=htmlspecialchars($tireqty);
    echo “$tireqty tireqty<br />”;
两种格式都是有效的,使用任何一种都是个人爱好。勇哥一个字符串的内容来代替一个变量的操作就是插补
注意,插补操作只是双引号引用的字符串的特性。不能将一个变量名称放置在一个由单引号引用的字符串中。在双引号中,变量名将被变量替代。而在单引号汇总,变量名称或任何其他的文本都会不经修改而发送给服务器

1.5.3变量和字面量
变量时表示数据的符号,字符串是数据本身
两种字符串的类型:一种是具有双引号的,而另一种是具有单引号的。php会计算双引号字符串的值,而单引号字符串将被当作字面量直接输出
变量用$开头
还有第3中指定字符串的方法:heredoc语句(<<<)。通过指定一个用来结束字符串的结束标记,heredoc语法允许指定长字符串。如:
  echo <<<theend
      line 1
      line 2
      line 3
  theend
theend 标记是非常明确的。它只需要保证不会出现在文本中。要关闭一个heredoc字符串,可以在每一行的开始处放置一个关闭标记
heredoc字符串是插补的,就像双引号字符串一样

1.6理解标识符标识符是变量的名称。函数和类的名称也是标识符
    *标识符可以是任何长度,而且可以有任何字母、数字、下划线组织
    *在PHP中,标识符是区分大小写的。$tireqty与$TireQty是不同的。对于这个规则函数名称是个例外-----函数名称不区分大小写
    *变量名称可以与函数名称相同
PHP的特性之一就是它不要求在使用变量之前声明变量。当第一次给一个变量赋值时,你才创建了这个变量

1.7检查变量类型

1.7.1PHP的数据类型
    integer(整数):用来表示整数
    float(浮点数,也叫double,双精度):用来表示所有实数
    string(字符串):用来表示字符串
    boolean(布尔):用来表示ture或者false
    array(数组):用来保存具有相同类型的多个数据项
    object(对象):用来保存类的实例
    NULL(空):没有被赋值、已经被重置或被赋值为特殊值NULL的变量就是NULL类型变量
    resource(资源):特点的内置函数(如数据库函数)将返回resource类型的变量。它们代表外部资源连接(如数据库连接)。基本上不能直接操作一个                                      resource变量,但是通常它们都将被函数返回,而且必须作为参数传递给其他函数
    callable类型通常都是苦于传递给其他函数的函数

1.7.2类型强度
PHP是一种弱类型,或者动态类型语言。在PHP中,变量的类型是由赋给变量的值确定的。
PHP可以在任何时间根据保存在变量中的值来变更变量类型
PHP将“自动地”获得输入的数据类型。一旦从变量中检索变量值,它将返回具有相同数据类型的数据

1.7.3类型转换
使用类型转换,可以将一个变量或值转换成另一种类型。如:
  $totalqty=0;
  $totalanount=(float)$totalqty;         //整型转换为浮点型

1.7.4可变变量
PHP提供了一种其他类型的变量:可变变量。可变变量允许我们动态地改变一个变量的名称
这个特性的工作原理是用一个变量的值作为另一个变量的名称。如:
   $varname='tireqty';
于是,就可以用$$varname取代$tireqty。如可以设置$tireqty的值:
   $$varname=5;
等价于:
   $tireqty=5;

1.8声明和使用常量
常量都是大写字母组成的
常量和变量的区别是:引用变量的时候用$开头,而常量直接使用常量名

1.9理解变量作用域
作用域是在一个脚本中某个变量在那些地方可以使用或可见。关于作用域PHP定义了如下6条规则:
   内置吵架全局变量可以在脚本的任何地方使用和可见
   常量一旦被声明,将可以在全局可见;也就是说,它们可以在函数内外使用
   在一个脚本中声明的全局变量在整个脚本中是可见的,但不是在函数内部
   函数内部创建的变量声明为全局变量时,其名称要与全局变量名称一致
   在函数内部创建并被声明为静态的变量无法在函数外部可见,但是可以在函数的多次执行过程中保持该值
   在函数内部创建的变量对函数来说是本地的,而当函数终止时,该变量也就不存在了超级全局变量的完整列表如下所示:
   $GLOBALS,所有全局变量数组(就像global关键字,这将允许在一个函数内部访问全局变量。如:以$GLOBALS['myvariable']的形式)
   $_SERVER,服务器环境变量数组
   $_GET,通过GET方法传递给该脚本的变量数组
   $_POST,通过POST方法传递给该脚本的变量数组
   $_COOKIE,cookie变量数组
   $_FILES,与文件上载相关的变量数组
   $_ENV,环境变量数组
   $_REQYEST,所有用户输入的变量数组,包括$_GET、$_POST和$_COOKIE所包含的输入内容(但是不包括$_FILES)
   $_SEEION,会话变量数组

1.10使用操作符
操作符是用来对数值和变量进行某种操作运算的符号。
操作符通常可以带有1个、2个或者3个运算对象,其中大多数操作符都带有两个运算对象。如:赋值操作符就带有两个对象----左边的表示保存值的位置,右边的表示表达式。这些运算对象叫操作数:也就是,要操作的对象

1.10.1算术操作符
1.10.2字符串操作符
1.10.3赋值操作符
1.10.3.1赋值运算返回值
1.10.3.2复合赋值操作符
   $a+=5;
等价于:
   $a=$a+5;
1.10.3.3前置递增递减和后置递增递减操作符
前置递增递减++、--
1.10.3.4引用操作符
引用操作符&也可以在赋值操作中使用。通常在将一个变量的值赋给另一个变量的时候,先产生一个变量的副本,然后再将它保存在内存的其他地方。如:
  $a=5;
  $b=$a;
这两行代码首先产生$a的一个副本,然后再将它保存到$b中,如果随后改变$a的值,$b的值将不会改变
要避免产生副本,可以使用引用操作符。如
  $a=5;
  $b=&$a;

  $a=7;      //$a and $b are now both 7
引用操作是非常尤其的。引用就像一个别名,而不是一个指针。$a和$b都是直线规律内存的相同地址。你可以通过重置使变量不指向原来的内存地址,如:
  unset($a);
重置操作并不会改变$b(7)的值,但是可以破坏$a和值在内存地址中的连接

1.10.4比较操作符
比较操作符用来比较两个值。返回true(非零)或false(零值)
1.10.4.1等于操作符
1.10.4.2其他比较操作符
恒等操作符===(三个等号)。只有当恒等操作符两边的操作数相等并且具有形同数据类型时,其返回值才为true。如:
0==‘0’将返回ture
0===‘0’返回的就不是ture
因为左边的0是一个整数,而另一个0则是一个字符串
!==不恒等操作符

1.10.5逻辑操作符
Not:操作符“!”。输出与输入永远相反
And:操作符“AND”。(输入) 有 0,(输出) 就有 0。
And:操作符“&&”。(输入) 有 0,(输出) 就有 0,比and操作符优先级高
Or:操作符“Or”。(输入) 有 1,(输出) 就有 1。
Or:操作符“||”。(输入) 有 1,(输出) 就有 1。比or操作符优先级高
XOR:互斥或闸,(输入) 相同,(输出) 为 0;(输入) 不同,(输出) 为 1。 (输入) 奇数个 1,(输出) 为 1;(输入) 偶数个 1,(输出) 为 0。

1.10.6位操作符
位操作符可以将一个整数当作一系列的位来处理。一般不常用
&(按位与),$a&$b : 将$a和$b的每一位进行与操作
|(按位或),$a|$b : 将$a和$b的每一位进行或操作
~(按位非),~$a : 将$a的每一位进行非操作
^(按位异或),$a^$b : 将$a和$b的每一位进行异或操作
<<(左移位),$a<<$b : 将$a左移$b位
>>(右移位),$a>>$b : 将$a右移$b位
1.10.7其他操作符

逗号操作符“,”是用来分隔函数和其他列表项的
两个特殊操作符new和->分别用来初始化类的十六和访问类的成员
10.7.1三元操作符
?:操作符语法格式如下:
  condtion ?value  if rtue : value if false
1.10.7.2错误抑制操作符
错误抑制操作符@可以在任何表达式前面使用,即任何有值的或者可以计算出值的表达式之前。如:
  $a=@(57/0);

如果没有@操作符,这一行代码将产生一个除0警告。使用这个操作符后,这个警告就会被抑制住


1.10.7.3执行操作符
执行操作符时间上是一对操作符,它是一对反向单引号(``)。反向单引号不是一个单引号。它在键盘的~位置
PHP会将反向单引号之间的命令当作服务器端命令行命令来执行。表达式的值就是命令的执行结果
如:
在类UNIX的操作系统中,可以使用:
    $out =`1s-1a`;
    echo `<pre>`.$out.`<\pre>`;
在windows服务器上,可以使用
    $out =`dir c:`;
    echo `<pre>`.$out.`<\pre>`;

这两个版本都会得到一个目录列表并且将该列表保存在$out中,然后,再将该列表显示在浏览器中或用其他方法来处理

1.10.7.4数组操作符
10.10.7.5类型操作符
只有一个类型操作符:instanceof。这个操作在面向对象编程中使用
instanceof操作符允许检查一个对象是否为特定类的实例
  class samoleClass{};
  $myObject =new sampleClass();
  if($myObject instanceof sampleClass)
    echo "myObhect is an instance of sampleClass";
1.11计算表单总金额将如下代码添加到PHP脚本
  1. $tireqty = $_POST['tireqty'];
  2.         $oilqty = $_POST['oilqty'];        
  3.         $sparkqty = $_POST['sparkqty'];                         //输入框输入的字符存储在数组_post中,并给变量赋值

  4.          $totalqty=0;                                                    //变量赋值
  5.          $totalqty=$tireqty+$oilqty+$sparkqty;               //计算商品数量
  6.          echo "<p>Items ordered:".$totalqty."<br />";    //输出$totalqty变量的值
  7.          $totalamount=0.00;                                         //变量$totalamount的类型转换为双精度两位小数
  8.          
  9.          define('TIRBPRICE',100);
  10.          define('OILPRICE',10);
  11.          define('SPARKPRICE',4);                                   //确定单价,大写字母组成的为常量,后边的数字是给常量赋值
  12.          
  13.          $totalamount=$tireqty*TIRBPRICE                    //计算总金额。单价*数量然后相加
  14.                    +$oilqty*OILPRICE
  15.                            +$sparkqty*SPARKPRICE;
  16.          echo "Subtotal:[        DISCUZ_CODE_0        ]quot;.number_format($totalamount,2)."<br />";          //输出总金额

  17.      $taxrate=0.10;        //local sales tax is 10%                      //设置税率为10%
  18.      $totalamount=$totalamount*(1+$taxrate);                       //计算出含税金额
  19.      echo "Total including tax:[        DISCUZ_CODE_0        ]quot;.number_format($totalamount,2)."</p>";  //输出变量$totalamount的值,数字2是格式输出,表示输出两位小数
复制代码



1.12理解操作符优先级和结合型


1.13使用变量处理函数
1.13.1测试和设置变量类型
大部分变量函数都与测试一个函数的类型有关。PHP中有两个最常见的变量函数,分别是gettype和settype。这两个函数具有如下所示的函数原型。通过它们可以获得要传递的参数和返回的结果:
  string gettype(mixed var);
  bool settype(mixed var,string type);要使用gettype()函数,必须先给他传递一个变量。它将确定变量的类型并且返回一个包含类型名称的字符串:bool、int、double、string、array、object、resource或NULL。如果变量类型不是标准类型之一,该函数就会返回“unknown type”(未知类型);
要使用srttype()函数,必须先给他传递一个要被改变类型的变量。以及一个包含了上述类型列表中某个类型的字符串。
提示:本书和PHP.net文档都提到了“混合”数据类型,事实上PHP并没有这个类型。但由于PHP在类型处理方面非常灵活,因此许多函数可以以多种(或者任何)数据类型作为参数。这些类型所允许的参数通常都是伪“混合”类型
我们可以按如下所示的方式使用这些函数:
   $a=56;                                      //变量赋值,此时变量为int型
   echo gettype($a).'<br />';           //输出获取到的变量a的数据类型,这里输出的a是integer
   settype($a,'float');                      //设置变量a为float型
   echo gettype($a).'<br />';           //输出获取到的变量a的数据类型,这里输出的a是double


PHP还提供了一些特点的类型测试函数。每一个函数都使用一个变量作为其参数。并且单号true或false。这些函数是:
  is_array(): 检查变量是否是数组
  is_double()、 is_float()、is_real() (所有都是相同的函数):检查变量是否是浮点数
  is_long、is_int()、is_integer()(所有都是相同的函数):检查变量是否是整数
  is_string():检查变量是否值字符串
  is_bool():检查变量是否是布尔值
  is_object():检查变量是否是一个对象
  is_resource():检查变量是否是一个资源
  is_null():检查变量是否是NULL
  is_scalar():检查该变量是否是标量,也就是:是否为整数、布尔值、字符串或浮点数
  is_numeric():检查该变量是否是任何类型的数据或数字字符串
  is_callable():检查该变量是否是有效的函数名称

1.13.2测试变量状态
PHP有几个函数可以用来测试变量的状态,第一个函数就是isset()。它具有如下的函数原型:
   bool isset(mixed var[,mixed var[,...]])
这个函数需要一个变量名称作为参数,如果这个变量存在则返回true,否则返回false。也可以传递一个由逗号间隔的变量列表,如果所有变量都被设置了,isset()函数将返回true。
可以使用与isset()函数相对应的unset()函数来销毁一个变量,它具有如下的函数原型:
  void umset(mixed var[,mixed var[,...]])
这个函数将销毁一个传进来的变量
函数empty()可以用来检查一个变量是否存在,以及它的值是否为非空和非0,相应的返回值true或false。它具有如下所示的函数原型:
  bool empty(mixed var)
看看这3个函数的实例:
         echo 'isset($tireqty):'.isset($tireqty).'<br />';                      //检测$tireqty变量状态,如果存在返回true,否则返回false
         echo 'isset($nothere):'.isset($nothere).'<br />';                  
         echo 'empty($tireqty):'.empty($tireqty).'<br />';                //检测$tireqty变量是否存在,以及它的值是否为非空和非0
         echo 'empty($nothere):'.empty($nothere).'<br />';            
无论表单输入什么值,还是根本就没有输入任何值,isset()函数中的变量都会返回1
而在empty()函数中,它的返回值取决于在表单域中输入的值
$tireqty变量不存在,因此在isset()函数中它将产生一个空白结果返回false,而在empty()函数中,将产生1(true)也就是假

1.13.3变量的重解释
可以通过调用一个函数来实现转换变量数据类型的目的。如下3个函数可以用来实现这项功能:
  int intval(mixed car[, int base=10])
  float floatval(mixed var)
  string strval(mixed var)
每个函数都需要接收一个变量作为其输入,然后再将变量值转换成适当类型返回。intval()函数也允许在要转换的变量为字符串时指定转换的进制基数(这样就可以将16进制的字符串转化成整数)

1.14根据条件进行决策
控制语句使程序语言中用来控制一个程序或脚本执行流程的结构。我们可以将它们分类为条件(或者分支)结构和重复结构(或循序结构)

1.14.4if语句
  if($totalqty==0)
    echo 'You did not order anything on the previous page!<be />';              //如果变量$totalqty为0输出本行
1.14.2代码块
花括号内的内容就是代码块

1.14.3 else语句

1.14.4elseif语句
在大多数情况下,决策都会面临多个选项。我们可以使用elseif语句来建立一个多选项序列。elseif语句是else和if语句的结合。通过提供一系列的条件,程序将检查每一个条件知道找到一个为true的条件Bob为轮胎订单的大客户准备了一定的折扣。其折扣方案如下所示:
   购买少于10个-----没有折扣
   购买少于10~49个-----5%折扣
   购买少于50~99个-----10%折扣
   购买少于100个以上-----15%折扣
我们可以使用条件表达式以及if和elseif语句来编写计算折扣的代码。在这个实例中,必须用“AND”操作符将两个条件结合成一个条件。如下代码所示:
        if($tireqty<10){
                $discount=0.00;
        }elseif(($tireqty>=10)&&($tireqty<=49)){
                $discount=0.05;
        }elseif(($tireqty>=50)&&($tireqty<=99)){
                $discount=0.10;
        }elseif($tireqty>=100){
                $discount=0.15;
        }
         echo "<p>discount:".$discount."<br />";  //折扣


1.14.5switch语句
在订单中加入一个调查问题。将如下所示的html代码插入订单的表单体中
<tr>
   <td>How did you find Bob's?</td>
   <td><select name="find">
   <option value="a">I'm a regular customer</option>
   <option value="b">Tv advertising</option>
   <option value="c">Phone directory</option>
   <option value="d">Word of mouth</option>  
   </select>   
   </td>
   </tr>


使用switch语句来处理find变量:
         switch($find){
                 case "a":
                 echo "<p>Regular customer.</p>";
                 break;
                 case "b":
                 echo "<p>Customer referred by Tv advert.</p>";
                 break;
                 case "c":
                 echo "<p>Customer referred by Phone directory.</p>";
                 break;
                 case "d":
                 echo "<p>We do not know how this customer found us.</p>";
                 break;
         }

1.14.6比较不同条件

1.15通过迭代实现充分动作
计算机非常擅长的一件事情就是自动地、重复地执行任务。如果某些任务需要以相同的方式执行多次,可以使用循环语句来重复程序中的某些部分
1.15.1while循环
PHP中最简单的循环就是while循环。就像if语句一样,它也依赖于一个条件
通常,当不知道所需要的重复次数时,可以使用while循环语句。如果要求重复固定的次数,可以考虑使用for循环语句
我们用while循环生成运费表
<!doctype html>
<html>
  <head>
    <title>Bob's Auto Parts - Preight Costs</title>
        </head>
<body>
<table style="border:0px;padding:3px">
<tr>
    <td style="backgrouder:#cccccc/text-align:center;">Distance</td>
        <td style="backgrouder:#cccccc/text-align:center;">Cost</td>
</tr>

<?php
$distance =50;
   while($distance<=250){
   echo"<tr>
   <td style=\"text-align:right;\">".$distance."</td>
   <td style=\"text-align:right;\">".($distance/10)."</td>
   </tr>\n";
   $distance+=50;
}
?>
</table>
</body>
</html>

1.15.2for循环和foreach循环
foreach专门用于访问数组

1.15.3do……while循环

1.16从控制结构或脚本中跳出
终止循环:break;跳转到循环体后执行
终止本次:continue;结束本次循环,跳转到下一次循环
结束脚本:exit。结束整个脚本,当执行错误检查时,这个语句非常有用

1.17使用其他控制结构语法
if($totalqty==0){
  echo "You did not order anything on the previous page!<br />";
  exit;
}
等价于
if($totalqty==0);
  echo "You did not order anything on the previous page!<br />";
  exit;
endif;

除过do……while不是用在末尾加end的方法结束,其他控制语句都可以替换掉花括号

1.18使用declare
PHP的另一个控制结构是declare结构,它并没想其他结构一样在日常变成中经常使用。这种控制结构的常见形式如下所示:
    declare (directive)
    {
     //block
    }
这种结构用来设置代码块的执行指令,也就是,关于后续代码如何运行的规则。目前,PHP提供了两个执行指令,ticks和encoding
插入指令ticks=n可以使用ticks。它允许在代码块内部每执行n行代码后运行特点函数,这对于性能调优和调试来说是非常有用的

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

8

主题

135

帖子

3270

积分

超级月卡

Rank: 7Rank: 7Rank: 7

积分
3270
 楼主| 发表于 2020-9-5 14:00:12 | 显示全部楼层
本帖最后由 why 于 2020-9-5 16:47 编辑

编辑了一章的数据发帖的时候发现浏览器自动退出了账号,再登陆就啥都没有了,以后再补上吧,都是些很基础的东西
2.6关闭文件
当使用完文件后,应该将其关闭。调用fclose()函数
  fclose(fp);
下面是processorder.php的完整脚本代码
  1. <?php
  2.          //create short variable names
  3.         $find=$_POST['find'];
  4.         $tireqty=$_POST['tireqty'];
  5.         $oilqty=$_POST['oilqty'];        
  6.         $sparkqty=$_POST['sparkqty'];
  7.         $address=preg_replace('/\t|\R/',' ',$_POST['address']);
  8.         $document_root=$_SERVER['DOCUMENT_ROOT'];
  9.     $date=date('H:i,jS F Y');        
  10. ?>


  11. <!doctype html>
  12. <html>
  13.   <head>
  14.     <title>Bob's Auto Parts - Order Results</title>
  15.         </head>
  16. <body>
  17.     <h1>Bob's Auto Parts</h1>
  18.         <h2>Order Results</h2>
  19.         <?php
  20.     echo "<p>Order processed at ".date('H:i:s, jS F Y')."</p>";
  21.     echo '<p>Your order is as follows:</p>';
  22.         
  23.            $totalqty=0;
  24.         $totalamount=0.00;
  25.         
  26.         define('TIRBPRICE',100);
  27.         define('OILPRICE',10);
  28.         define('SPARKPRICE',4);                //单价
  29.         
  30.         $totalqty=$tireqty+$oilqty+$sparkqty;
  31.         echo "<p>Items ordered:".$totalqty."<br />";//商品总数
  32.         
  33.         if($totalqty==0){
  34.                 echo "You did not order anything on the previous page!<br />";
  35.         }
  36.         else{
  37.                 if($tireqty>0){
  38.                         echo htmlspecialchars($tireqty).'tires<br />';
  39.                 }
  40.                 if(oilqty>0){
  41.                         echo htmlspecialchars($oilqty).'bottles of oil<br />';
  42.                 }
  43.                 if(sparkqty>0){
  44.                         echo htmlspecialchars($sparkqty).' spark plugs<br />';
  45.                 }
  46.         }
  47.         
  48.         $totalamount=$tireqty*TIRBPRICE
  49.                    +$oilqty*OILPRICE
  50.                            +$sparkqty*SPARKPRICE;
  51.          echo "Subtotal:[        DISCUZ_CODE_0        ]quot;.number_format($totalamount,2)."<br />";    //总金额
  52.          
  53.          $taxrate=0.10;        //local sales tax is 10%
  54.      $totalamount=$totalamount*(1+$taxrate);
  55.      echo "Total including tax:[        DISCUZ_CODE_0        ]quot;.number_format($totalamount,2)."</p>";  //含税金额
  56.         
  57.         echo "<p>Address to ship to is ".htmlspecialchars($address)."</p>";
  58.         $outputstring=$date."\t".$tireqty."tires \t".$oilqty." oil\t"
  59.                          .$sparkqty." spark plugs\t\[        DISCUZ_CODE_0        ]quot;.$totalamount
  60.                          ."\t".$address."\n";
  61.         //open file for appending                                         
  62.         $fp=fopen("$document_root/../orders/orders.txt",'ab');
  63.            if(!$fp){                                                                                   //”!“是取反。如果$fp返回false则输出trun,
  64.             echo "<p><strong>You order could not be processed at this time.
  65.                    .Please try again latger.</strong></p>";        //输出一个错误信息提示
  66.               exit;                                                                                                    //退出脚本
  67.         }
  68.                
  69.         flock($fp,LOCK_EX);
  70.         fwrite($fp,$outputstring,strlen($outputstring));
  71.         flock($fp,LOCK_UN);        
  72.         fclose($fp);

  73.         echo"<p>Order written.</p>";
  74.     ?>               
  75. </body>
  76. </html>
复制代码




2.7读文件
现在,Bob的客户块通过web下订单了,但是如果Bob的员工希望查看这些订单,它们就必须自己打开这个文件
可以创建一个web界面,从而方便Bob的员工读取这些文件.代码如下
  1. <?PHP
  2. //create short variable name
  3. $document_root=$_SERVER['DOCUMENT_ROOT'];
  4. ?>
  5. <!doctype html>
  6. <html>
  7.   <head>
  8.     <title>Bob's Auto Parts - Order Results</title>
  9.         </head>
  10. <body>
  11.   <h1>Bob's Auto Parts</h1>
  12.   <h2>Customer Orders</h2>
  13.   <?php
  14.     @$fp=fopen("$document_root/../orders/orders.txt",'rb');   //打开成功fp获得指向文件的指针
  15.         flock($fp, LOCK_SH);  //取得fp指向的文件共享锁定(读操作)
  16.        
  17.         if(!$fp){                //打开文件失败fp得到空指针true,如果fp为true输出false,执行本段提示
  18.                 echo "<p><strong>No orders pending.<br />
  19.                      Please try again later.</strong></p>";
  20.                 exit;         
  21.         }
  22.         while(!feof($fp)){               //当 fp指向的文件内容没有出现结束符标志
  23.                 $order=fgets($fp);           //从fp指向的文件读取一行内容到变量order
  24.                 echo htmlspecialchars($order)."<br />";  //输出读到的内容
  25.         }
  26.         flock($fp,LOCK_UN);//释放fp指向的文件共享锁定(无论共享或独占)
  27.         fclose($fp);       //关闭文件
  28.   ?>
复制代码


2.7.1以只读模式打开文件:fopen()
我们仍然使用fopen()函数打开文件,这这个实例中,以只读模式打开这个文件,所以我们使用了"rb"文件模式
      $fp=fopen("$document_root/../orders/orders.txt",'rb');   //以二进制只读模式打开文件

2.7.2知道何时读完文件:feof()
feof()(file end of file)  检测文件结尾标志符,如果指针指向结尾标志符返回true

2.7.3每次读取一行数据:fgets(),fgetss(),fgetcsv()
  $order=fgets($fp);
从文件中每次读入一行,读到换行符停止,或者eof标志

  string fgetss(resource fp[, int lengrth[, string allowble_tags]]);
和fgets功能类似,但它可以过滤字符串中包含PHP和HTML标记

  $order=fgetcsv($fp,0,"t");
从文件中读取一行,并且在有制表符'\t'的地方将文件内容分行

2.7.4读取整个文件:readfile(),fpassthru(),file()以及file_get_contents()
     readfile("文件地址")
打开这个文件,并且将文件内容输出到标准输出(浏览器)中,然后关闭文件,函数原型如下:
     int readfile(string filename,[bool use_include_path[, resource context]]);
第二个可选参数指定了PHP是否应在include_path中查找文件;可选的context参数只有在文件远程打开是才使用

    fpassthru($fp);
操作成功,函数返回true,否则返回false

   $filearray=file("文件地址")
文件读入到filearray数组中,并且把文件内容输出到浏览器

file_get_contents()函数与readfile()相同,但是该函数将以字符串的形式返回文件内容

2.7.5读取一个字符:fgetc()
  while (!feof(fp)){
       $char=fgetc(fp);                                              //读入一个字,存入变量char中
       if(!feof(fp)){                                                    //
           echo ($char=="\n"?"<br />char");
       }
   }

2.7.6读取任意长度:fread()
  string fread(resourcr fp,int lenfth);
该函数返回时,要么读满了length参数所指定的字节数,要么读到了网络数据包的结束

2.8使用其他文件函数
查看文件是否存在:file_exists()
       if (file_exists("文件地址")){
           echo 'There are order waiting to be processed.';
        }                                       
       else{
            echo "There are currently no order."
        }
不打开文件检测文件是否存在

确定文件大小:filesize()
        echo filesize("文件地址");
它以字节位单位返回一个文件的大小

删除一个文件:unlink()
    unlink("文件地址");
如果无法删除这个文件,函数将返回false

在文件中定位:rewind(),fseek(),ftell()
rewinfd()函数可以将文件指针复位到文件的开始
ftell()函数可以以字节位单位报告文件指针当前在文件中的位置
fseek()函数将文件指针指向文件的某个位置

文件锁定:flock()
flock($fp,LOCK_SH);    该操作锁定,以为着文件可以共享,其他人可以读该文件
flock($fp,LOCK_EX);    写操作锁定,这是互斥的,该文件不能共享
flock($fp,LOCK_UN);   释放已有的锁定
flock($fp,LOCK_NB);   防止在请求加锁时发生阻塞(windows不支持)
如果有两个脚本同时申请对一个文件加锁.这将导致竞争条件的问题,这两个进程将竞争加锁,但是无法确定哪一个进程会成功,这就导致更多的问题,使用数据库管理系统可以很好的解决这个问题

2.10更好的方式:数据库管理系统

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

8

主题

135

帖子

3270

积分

超级月卡

Rank: 7Rank: 7Rank: 7

积分
3270
 楼主| 发表于 2020-9-5 18:44:11 | 显示全部楼层
本帖最后由 why 于 2020-9-6 11:16 编辑

第3章 使用数组
3.1什么是数组
PHP允许间隔性地使用数字或字符串作为数组的索引.可以将数组的索引设置为传统的数字型,也可以将索引设置为任何有意义的类型

3.2数字索引数组
   $products=array('Tires','oil','Spark Plugs');
以上代码将创建一个名为$products的数组,它包含3个给定值---'Tires','oil','Spark Plugs'.array()是一个语句,而不是一个函数.PHP5.4开始可以使用如下方式创建数组
   $products=['Tires','oil','Spark Plugs'];

   $number=range(1,10);             //创建一个一维数组,数组名number,下标1~10
   $number=range(1,10,2);           //创建一个一维数组,数组名number,元素步幅为2,下标1,3,5,7,9
   $letters=range('a','z');              //创建一个一维数组,数组名letters,元素步幅为2,下标a~z

    $products[3]='Fuses';              //在数组products末尾增加一个元素(如果数组只有2个元素的话),否则就是赋值给第3个元素.也可以把[]换成{},如下:
    $products{3}='Fuses';
    echo "$products[0] $products[1] $products[2]"           //输出数组元素的值

    for($i=0;$i<3;$i++)
       {
          echo $products[ i ]." ";
         }                                            //循环输出数组中的元素

    foreach($products as $current)
        {
          echo $current." ";
        }                                             //依次将保存在$current中的每一个元素输出,foreach是专为数组设计的

    $prices=array('Tires=>100','oil=>10','Spark Plugs=>4');   //相当于给数组赋值$prices['Tires']元素的值为100.Tires称为键,100称为值

当数组的元素不为数字时无发使用for循环语句对数组进行操作,但可以使用foreach循环或list()和each()结构
        foreach ($prices as $key=>$value){
         echo $key."-"$value."<br />";
        }                                              //输出$prices数组中的键值和值 ,$key=>$value表示键值和值一一对应

如下代码使用each()结构列出$prices数组中的内容
       while ($element=each($prices)){                            //each($prices)函数取当前数组的元素,然后赋值给数组element,返回的元素包含了键值和值
         echo $element['key']."-".$element['value'];             //输出数组的键值和值
         echo "<br />"                                                     //输出换行符
       }

还有一种更好并常见的方式来完成相同的操作.list()可以将一个数组分解为一系列的值
      while (list($product,$prices)=each(/$prices)){          //取得当前数组的元素,赋值给两个变量$product,$prices
        echo $product."-".$price."<br />";                        //输出两个变量的值

      }
在使用each()时,数组将记录当前元素.如果希望在脚本中多次使用数组,需要使用reset()函数将当前元素设置为数组开始
      reset($prices);                                                     //将当前元素设置为数组的开始,也就是设置为数组的第一个元素
      while (list($product,$prices)=each($prices)){          //取得当前数组的元素,赋值给两个变量$product,$prices
        echo $product."-".$price."<br />";                        //输出两个变量的值

      }


$a+$b表示$a和$b联合,数组b将被附加到数组a中,但是任何关键字冲突的元素将不会被添加

数组排序
  $products=array('Tires','oil','Spark Plugs');
  sort($products);                                      //区分大小写按字母升序排序
sort()函数的第二个参数是可选的.这个可选参数值包括
    SORT_REGULAR(默认值)
    SORT_NUMERIC
    SORT_STRING
    SORT_LOCALE_STRING;根据当前系统locale按字符串形式对数组进行排序,不同的locale(地区)的排序结果不同
    SORT_NATURAL           ;自然排序
    SORT_FLAG_CASE        ;与SORT_NUMERIC或SORT_STRING组合使用,可以使用位操作符&来组合使用
  sort($products,SORT_STRING & SORT_FLAG_CASE );         //忽略大小写进行排序

  $prices=array('Tires=>100','oil=>10','Spark Plugs=>4');
  asoer($prices);                       //以数组元素值排序


  $prices=array('Tires=>100','oil=>10','Spark Plugs=>4');
  ksoer($prices);                       //以数组键值排序,也就是数组下标(这里得下标是文字,所有是按键值的首字母进行升序排序)

反向排序rsort() , arsort() , krsort().与上边3个函数的排序正好相反,是降序排序

  $products=array(array('TIR','Tires',100),
                           array('OIL','Oil',10),
                           array('SPK','Spark Plugs',4));          //设置二维数组,有两个键值和一个值
  array_multisort($products);                                    //对二维数组排序
排序结果是:该函数将对$products数组中每个子数组的第一个元素按常规升序进行排序
对于排序,可以用SORT_ASC或SORT_DESC指定升序或降序排序
对于排序类型,array_multisort()函数与sort()函数一样,支持相同设置
需要注意的是,对于关键字是字符串的array_multisort()函数将维护键-值关联,而对于数值,则不会维护此关联

用户定义排序
   function compare($x,$y){                      //定义一个compare函数,它有两个变量x和y,function是定义函数的关键字
      if($x[1]==$y[1]){
         return 0;
      }
      else if($x[1]<$y[1]){
         return -1;
      }
      else{
         return 1;
      }
   }
   usort($profucts,'compare');                 //调用自定义函数compare(),返回值作为指定排序类型的参数

usort()中的"u"代表"user",因为这个函数要求传入用户定义的比较函数,asort()和ksort()对应的版本uasort()和uksort也要求传入用户自定义的比较函数
自定义排序函数的反序:用户自定义的排序函数没有反向变体,需要自己写比较函数
  function compare($x,$y){                      //定义一个compare函数,它有两个变量x和y,function是定义函数的关键字
      if($x[2]==$y[2]){
         return 0;
      }
      else if($x[2]<$y[2]){
         return 1;
      }
      else{
         return -1;
      }
   }
   usort($profucts,'compare');                 //调用自定义函数compare(),返回值作为指定排序类型的参数,调用参数是就进行反向排序了

对数组进行重新排序
shuffle()将数组各元素进行随机排序
array_reverse给出一个按原来数组顺序的反向排序
只用PHP为Bob的汽车配件商店制作一个动态首页
  1. <?PHP
  2.   $pictures=array('brakes.png','headlight.png','skpark_plug.png',
  3.                   'steering.png','tire.png','wiper_blade.png');
  4.   shuffle($pictures);                                                           //随机排序$pictures数组中的元素
  5. ?>
  6. <!doctype html>
  7. <html>
  8.   <head>
  9.     <title>Bob's Auto Parts</title>
  10.         </head>
  11. <body>
  12.   <h1>Bob's Auto Parts</h1>
  13.     <div align="center">
  14.           <table style="width:100%;border:0">
  15.             <tr>
  16.         <?php
  17.                 for($i=0;$i<3;$i++){
  18.                         echo "<td style="width:33%;text-align:center:">
  19.                         <img src="";                                                        
  20.                         echo $pictures[$i];
  21.                         echo ""/></td>";                                  //循环输出3个元素
  22.                 }
  23.                 ?>
  24.                 </tr>
  25.           </table>
  26.     </div>
  27. </body>
  28. </html>
复制代码


逆序数组内容
  $numbers=range(1,10);                          //顺序数组
  $numbers=array_reverse($numbers);       //对$numbers数组进行逆序排列,得到的数组存放在$numbers数组

  $numbers=array();
  for($i=10;$i>0;$i--){
    array_push($numbers,$i);                     //array_push将每个新元素添加到数组末尾,与其相反的是array_pop(),用来删除并返回数组末尾的一个元素
  }                                                          //逆序创建数组,数组元素从$numbers[10]起,下标顺序减1

  $numbers=range(10,1,-1);                     //步进加-1.每创建一个数组下标加-1

从文件载入数组
  使用PHP显示Bob的订单内容
  1. <?PHP
  2. //create short variable name
  3. $document_root=$_SERVER['DOCUMENT_ROOT'];
  4. ?>
  5. <!doctype html>
  6. <html>
  7.   <head>
  8.     <title>Bob's Auto Parts - Order Results</title>
  9.         </head>
  10. <body>
  11.   <h1>Bob's Auto Parts</h1>
  12.   <h2>Customer Orders</h2>
  13.   <?php
  14.     $orders=file("$document_root/../orders/orders.txt");           //打开文件
  15.         $number_of_orders=count($orders);                             //统计数组中的元素个数
  16.         if($number_of_orders==0){                                         //如果统计的结果等0执行花括号内容
  17.                 echo "<p><strong>No orders pending.<br />
  18.                      Please try again later.</strong></p>";
  19.         }
  20.         for($i=0;$i<$number_of_orders;$i++){                        //否则执行这里,设变量i为0,统计的数组元素大于i
  21.                 echo $orders[$i]."<br />";                                        //输出数组元素,每次循环输出下一个元素
  22.         }
  23.         ?>
  24. </body>
  25. </html>
复制代码


用PHP分隔,格式化并显示Bob的订单内容
  1. <?PHP
  2. //create short variable name
  3. $document_root=$_SERVER['DOCUMENT_ROOT'];
  4. ?>
  5. <!doctype html>
  6. <html>
  7.   <head>
  8.     <title>Bob's Auto Parts - Customer Orders</title>
  9.         <style type="text/css">
  10.         table,th,td{
  11.                 border-collapse:collapse;
  12.                 border:1px solid black;
  13.                 padding:6px;
  14.         }
  15.         th{
  16.                 background:#ccccff;
  17.         }
  18.         </style>
  19.         
  20. </head>
  21. <body>
  22.   <h1>Bob's Auto Parts</h1>
  23.   <h2>Customer Orders</h2>

  24.   <?php
  25.     //read in the entire file
  26.     //each order becomes an element in the array
  27.     $orders=file("$document_root/../orders/orders.txt");
  28.         //count the number of orders in eht array
  29.         $number_of_orders=count($orders);     //取数组中的元素数目
  30.         if($number_of_orders==0){
  31.                 echo "<p><strong>No orders pending.<br />
  32.                      Please try again later.</strong></p>";
  33.         }
  34.         
  35.         echo "<table>\n";
  36.         echo "<tr>
  37.                 <th>Order Date</th>                           
  38.                         <th>Tires</th>                           
  39.                         <th>Oil</th>                           
  40.                         <th>Spark Plugs</th>                           
  41.                         <th>Total</th>
  42.             <th>Address</th>                        
  43.                   <tr>";

  44.         for($i=0;$i<$number_of_orders;$i++){
  45.                 //split up each line
  46.                 $line=explode("\t",$orders[$i]);     //以\t分隔数组,分隔后得到一个数组
  47.                 //keep only the number of items ordered
  48.                 $line[1]=intval($line[1]);           //取变量的整数值
  49.                 $line[2]=intval($line[2]);
  50.                 $line[3]=intval($line[3]);           
  51.                 //output each order

  52.         echo "<tr>
  53.                         <td>".$line[0]."</td>
  54.                         <td style="txet-align:right;">".$line[1]."</td>
  55.                         <td style="txet-align:right;">".$line[2]."</td>
  56.                         <td style="txet-align:right;">".$line[3]."</td>
  57.                         <td style="txet-align:right;">".$line[4]."</td>
  58.                         <td>".$line[5]."</td>
  59.                   <tr>";
  60.                   
  61.         }
  62.                 echo "</table>";        
  63.         ?>
  64. </body>
  65. </html>
复制代码



执行其他数值操作
current($array_name);返回数组第一个元素的值
each($array_name);返回一个数组,数组两个元素(1 和 Value)包含键值,两个元素(0 和 Key)包含键名
next($array_name);指向下一个元素,并返回值
prev($array_name)将指针指向上一个元素,并返回元素的值
reset($array_name)将指针指向第一个元素,并返回元素的值
end($array_name)将指针指向最后一个元素,并返回元素的值

对数组每一个元素应用函数:array_walk(元素键值,元素键名)
  1. <?php
  2.   function my_multiply(&$value,$sky,$factor){          //定义函数my_multiply,包含3个值
  3.     $value*=$factor;         //$value=$value*$factor        //$value=$value*$factor
  4.         echo "$value \t";                                           //输出结果为3 6 9 12
  5.   }
  6.   $array=[1,2,3,4];
  7. array_walk($array,'my_multiply',3);                       /*3个参数传递给函数my_multiply,第一个数组,第二个数组键值(也就是下标),用数组中的每个元素的值和第3个值相乘的结果放在每个元素中,$value前面有&符,是需要更改数组元素值的*/
  8. ?>
复制代码


统计数字元素个数
count(数组);统计数组元素个数
sizeof(数组);统计数组元素个数
array_count_valuse(数组);返回一个数组,这个数组包含被统计数组中的元素出现的次数.如:
    $array=arra(4,5,1,2,3,1,2,1);              //定义数组array
    $ac=array_count_valuse($array);        //$ac是数组,键值是$array元素的值,值是$array元素出现的次数

将数组转换成标量变量
extract(关键字数组,可选参数);将数组中的关键字设为变量名,变量值是对应的元素值.可选参数用来处理处理后的变量名冲突问题
    EXTR_OVERWRITE(默认可选参数):当设变量的时候发生冲突覆盖已有变量
    EXTR_PREFIX_ALL(可选参数):使所以变量名称之前加上有prefix参数的指定值.必须提供prefix参数.如:
           $array=array('key1'=>'value1','key2'=>'value2','key3'=>'value3');         //关键字数组,键名为key,键值为value
           extract($array,EXTR_PREFIX_ALL,'my_prefix');                                     //创建的变量名前加上前缀my_prefix
           echo "$my_prefix_key1 $my_prefix_key2 $my_prefix_key3";                 //输出变量,显示结果是value1 value2 value3
以数字开始或包含空格的关键字将被跳过,意思就是数组的下标不能是数字

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

8

主题

135

帖子

3270

积分

超级月卡

Rank: 7Rank: 7Rank: 7

积分
3270
 楼主| 发表于 2020-9-6 17:34:28 | 显示全部楼层
本帖最后由 why 于 2020-9-7 13:34 编辑

这一章都给我难哭了,太难了.谁说的比c简单,脑子都搞疼了,这玩意函数真多不知道能用上的有几个
第4章 字符串操作与正则表达式

邮件表单内容基本脚本
  1. <?php
  2. //create short varbiable names
  3. $name=$_POST['name'];
  4. $email=$_POST['email'];
  5. $feedback=$_POST['feedback'];

  6. //set up some static information
  7. $toaddress="kakawo@163.com";                   //邮件地址

  8. $subject="Feedback from web site";               //邮件主题

  9. $mailcontent="cuseomer name:".filter_var($name)."\n".
  10.              "customer email:".$email."\n".
  11.                          "customer comments:\n".$feedback."\n";         //邮件内容
  12.                         
  13. $fromaddress="From:kakawo@163.com";

  14. //invoke mail() function to sent mail
  15. mail($toaddress,$subject,$mailcontent,$fromaddress);                /*第一个参数收件地址,第二个参数主题,第三个参数消息内容,第四个参数可以用来发送任何额外的,有效的邮件header*/                 
  16. ?>
  17. <!doctype html>
  18. <html>
  19.   <head>
  20.     <title>Bob's Auto Parts - Feedback Submitted</title>
  21. </head>
  22. <body>
  23.   <h1>Feedback Submitted</h1>
  24.   <h2>Your feedback has been sent.</h2>
  25. </body>
  26. </html>
复制代码

这段代码无法测试,可能是我的环境有问题,尝试了网上的方法也没能解决,代码第3,4,5行报错,应该是PHP邮件系统的问题,但我不知道问题出在哪里.我们先往下看

字符串截断
$name=trim(字符串,字符);         //去除字符串开始和结束位置的空格.第2个参数为选填,去掉字符串首尾包含的参数2的字符
$name=ltrim(字符串,字符);        //去除字符串开始位置的空格.第2个参数为选填,去掉字符串首包含的参数2的字符
$name=rtrim(字符串,字符);        //去除字符串结束位置的空格.第2个参数为选填,去掉字符串尾包含的参数2的字符

htmlspecialchars(字符串,flags,encoding,double_encode);    //将字符串转换为对应的HTML实体,就是字符串中的符号是否需要显示在浏览器中(如< >" " ' '这类)
    第一个可选参数flags:指定了如何完成翻译.默认ENT_COMPAT双引号需要编码翻译,单引号不需要.默认ENT_HTML401表示必须被当作HTML4.01
    第二个可选参数encoding:指定了转换的编码方式,默认UTF-8
    第三个可选参数double_encode:指定了是否需要对HTML实体进行编码

str_replace(字符1,字符2,字符串);         //从字符串中查找字符并替换
   第一个参数,需要从字符串中查找的字符
   第二个参数,用字符2替换掉字符串中的字符1

nl2br(字符串);        //在字符串中的\n之前插入一个<br /> ,浏览器的显示效果就是长字符串进行了换行

printf("aaaa %s",$b);    //以%s格式输出$b到aaaa后.         
printf("aaaa %.2f",$b);    //以2位小数格式输出$b到aaaa后.   
printf("aaaa %s",$b);    //以%s格式输出$b到aaaa后.

strtoupper(字符串);      //将字符串转换为大写
strtolower(字符串);      //将字符串转换为小写
ucfirst(字符串);            //如果参数的第一个字符是字母,将其转换成大写字母
ucwoeds(字符型);        //将字符串中以字母为开始的每个单词的单一个字符转换成大写字母

使用字符串函数连接和分隔字符串
explode(字符,字符串);   //将字符串中的内容用字符分隔,分隔后得到一个数组(替换字符串中和字符参数相同的字符)
implode(字符,数组);      //从数组中取出元素,用字符进行连接
join(字符,数组);           //从数组中取出元素,用字符进行连接

sterok(字符串,字符);    //将字符串中的内容用字符分隔,每次分隔得到一个新的字符串,每次只能得到一个字符串
substr(字符串,int数值);   //取字符串中int个字符后的字符,比如参数int为3,返回字符串3个字符后的所有字符.如果参数2为负数,从字符串末尾作为起点输出2个字符后的所有字符
substr(字符串,int数值1,int数值2);            //取字符串中int1个字符后的int2字符

字符串比较
stcmp(字符串1,字符串2);   //相等返回0.如果按字典顺序字符串1在字符串2后(字符串2大于字符串1)就返回正数,否则返回负数.区分大小写
strcasecmp(字符串1,字符串2);   //不区分大小写,其他与stcmp()相同
strnacasecmp(字符串1,字符串2);   //不区分大小写,按"自然顺序排序",(10>2就是自然顺序,和字典顺序正好相反)

strlen(字符串);    //返回字符串的长度

使用字符串函数匹配和替换子字符串
strstr(字符串1,字符串2);  //判断字符串1中是否有字符串2,如果有删除字符串1中字符串2首字符(不包括首字符)前的字符,然后输出
strstr(字符串1,字符串2,treu);  //如果有第三个参数true.删除字符串1中从字符串2首字符(包括)后的所以字符.然后输出
strrchr(字符串1,字符串2);     //功能同strstr()

strpos(字符串1,字符串2);    //功能和strstr()一样,但返回的是字符串2的首字符首次出现在字符串1的位置(int值)
strpos(字符串1,字符串2,int数值);    //功能和strstr()一样,但返回的是字符串2的首字符出现在字符串1(从int开始作为起点寻址)的位置(int值)
strrpos(字符串1,字符串2);    //功能和strstr()一样,但返回的是字符串2的首字符最后一次出现在字符串1的位置(int值)

str_replace(字符串1,字符串2,字符串3);  //把给定字符串3中的字符串1换成字符串2,字符串3可以是一个数组substr_replace(字符串1,字符串2,int数值);   //从字符串1的int值作为起点,替换成字符串2,如果int为负数,从后往前开始计算起点并替换

正则表达式
分隔符:最常用的分隔符是/,如果要编写一个匹配"shop"的正则表达式,可以使用:/shop/
           如果要在正则表达式中匹配字符"/": /http:\ / \ / /
           如果模式包含了多个分隔符,需要考虑选择不同的分隔符如#:   #http://#
           有时,可能需要在结束分隔符后添加一个模式修饰符如: /shop/i    .该模式以不区分大小写的方式匹配"shop"
           "!"是目前最常用的修饰符

可以使用字符"."作为匹配除换行符(\n)之外的任何字符的通配符.如: /.at/     可以匹配"cat""sat""mat"等字符串,通常这种匹配适用于操作系统的文件名匹配
如果要限定第一个字符是字母.可以这样指明: /[a-z]at/   ,任何包括[]的内容都是一个字符类,方括号中的表达式只匹配一个字符
用也限定第一个字符非字母.可以这样写: /[^a-z]at/      ,"^"表示否
/[[:alpha]1-5]/   表示字母字符或数字字符1-5的字符类
在正则表达式中,可以使用三个特殊字符代替指定特定字符串或字符类多次出现.符号"*"表示这个模式可以重复出现0次或多次,符号"+"表示这个模式可以重复出现1次或多次."?"表示这个模式可以出现1次或0次.如:/[[:alnum:]+]/   .表示至少有一个字母字符
/(very)*large/    表示至少这些字符串中的一个需要匹配该模式
/(very){2}/        {}中使用数字表达式来指定内容运行重复的次数,表示字符串可以重复2次
/(very){1,3}/      表示字符串可以重复1-3次,表示匹配"very","very very","very very very"
/^bob/              从字符串开始处匹配bob
/com$/              匹配以com结尾的字符串
/^[a-z]$/           只匹配包含a-z之间一个字符的字符串,也就是匹配单个字母
如果要匹配特殊字符如:"." , "{" , "$" 必须在它们前面加反斜杠(\),如果要匹配反斜杠,则必须要用两个反斜杠来表示
必须用单引号来引用正则表达式

转义序列是一种模式定义,它以反斜杠字符(\)为开始,转义序列有以下几种用法:
      第一种,反斜杠用来转义特殊字符
      第二种,反斜杠用在代表非打印字符的字符前面
回溯引用也叫反向引用
/^([a-z]+) \1 black sheep/   
回溯引用这个书上介绍了半天都没能看懂,书上是这么说的"找到匹配前面子表达式的内容,并且与该内容完全相同的内容再次出现在后续内容"
我来翻译翻译这段正则表达式
[a-z]+    表示匹配一个或多个字符字符
^           从字符串开始处匹配
\1          调用第1个子表达式.一般从第1个子表达式开始调用,第0个用来替代整个正则表达式一般不常用.这里得第1个子表达式就是([a-z]+)
这样就清楚多了
先匹配到black sheep,在black sheep前面的字符串必须和它前面的字符串一样
所以书上的bba bba black sheep被匹配到了.因为black sheep前面是bba,bba之前还是bba
而blah bba black sheep就没有被匹配到,因为首先匹配到black sheep后,black sheep前面是bba,bba前面的blah和不一样

判断某个位置左/右侧是否符合要求称为断言

有字符串hello the world 用断言匹配
\b\w+(?=ld\b),则会输出wor   
          \b单词边界,\w单词字符,?=ld\b匹配ld的位置前边的值.先匹配到ld,然后使用两个\b找到单词边界,确定单词为world,然后输出前边的字符wor
          (?=exp) :定义目标字符串结束位置

(?<=\bhe)\w+\b。则会匹配出值llo
           (?<=\bhe)匹配bh的位置后面的值,\w单词字符,\b单词边界.先匹配到bh然后使用两个\b找到单词编辑,确定单词为hello,然后输出he后边的字符llo
           (?<=exp):定义目标字符串起始位置

  (?!exp)用于匹配值后面不能是exp
\bhe(?!o)\w,则匹配出hell
           \b单词边界,字符he,?!o匹配o但后面不能是o,也就是如果字符串时see you too的话出现两个o就不能匹配到,先匹配出只有一个o的单词,然后用\b找到单词边界,输出单词前边的字符hell.
          (?!exp):定义目标字符串结束位置

(?<!\d)[a-z]\w+,则匹配出hello the world
           ?<!\d匹配起始位置不能是十进制数字,[a-z]小写字母,\w单词字符,整个字符串都没用十进制数字开始的所以全部输出
           (?<!exp):定义目标字符串起始位置

实际就是给定一个值,然后寻找通过这个值寻址到这个单词,输出这个单词的前或后段字符

preg_match(正则表达式,字符串,多维数组,可选参数,可选参数);
           在字符串中使用正则表达式搜索匹配的结果存在多维数组中,每个数组元素对应一个子表达式的匹配
           第3个参数值为:
                  PREG_PATTERN_ORDER: 结果排序为$matches[0]保存完整模式的所有匹配, $matches[1] 保存第一个子组的所有匹配,以此类推。
                  PREG_SET_ORDER: 结果排序为$matches[0]包含第一次匹配得到的所有匹配(包含子组), $matches[1]是包含第二次匹配到的所有匹配(包含子组)的数组,以此类推。
                  PREG_OFFSET_CAPTURE: 如果这个标记被传递,每个发现的匹配返回时会增加它相对目标字符串的偏移量。
                  (注意不能同时使用PREG_PATTERN_ORDER和 PREG_SET_ORDER)
          第4个参数用来指定从字符串的第几个字符作为起始查询位置,一般默认从0位置
         参数匹配成功返回1,失败返回0,错误返回false,必须用"==="检查返回值

preg_replace ( 正则表达式 , 字符串1 , 字符串 ,替换次数 , 替换执行的次数);
           在字符串中用正则表达式查找,符合正则表达式的字符串用字符串1进行替换
           参数4,5为可选.替换次数默认为-1代表无限次

preg_split(正则表达式,字符串,可选参数,可选参数);
           用正则表达式分隔字符串,返回一个数组
           第三个参数为:限制子字符串数组的元素个数,默认-1,表示无限制
           第四个参数为
                     PREG_SPLIT_NO_EMPTY: 如果这个标记被设置, preg_split() 将进返回分隔后的非空部分。
                     PREG_SPLIT_DELIM_CAPTURE: 如果这个标记设置了,用于分隔的模式中的括号表达式将被捕获并返回。
                     PREG_SPLIT_OFFSET_CAPTURE: 如果这个标记被设置, 对于每一个出现的匹配返回时将会附加字符串偏移量. 注意:这将会改变返回数组中的
每一个元素, 使其每个元素成为一个由第0 个元素为分隔后的子串,第1个元素为该子串在subject 中的偏移量组成的数组。
                     (可以组合使用(以位或运算 | 组合))







这一章真是太难太难太难了,我太难了我
回复

使用道具 举报

8

主题

135

帖子

3270

积分

超级月卡

Rank: 7Rank: 7Rank: 7

积分
3270
 楼主| 发表于 2020-9-7 09:59:48 | 显示全部楼层
本帖最后由 why 于 2020-9-7 19:33 编辑

第5章 代码重用与函数编写
require('reusable.PHP');          //引入一个PHP文件
include('reusable.PHP');          //两个函数功能一样                                                                                                                                                          readfile()                              //读入一个文件并以文本或HTML输出
                                                                                                                                    
如果使用php.ini中如下两个配置,可以不使用以上两个函数载入页眉和脚注:
auto_prepend_file =              ;载入网页页眉        
auto_append_file =               ;载入网页脚注

调用函数时函数名不区分大小写,但函数变量要区分大小写


函数声明格式:
function my_function(){                             //function函数声明关键字,
    echo 'my function was called';
  }   

函数命名具有如下几个限制:
  函数名称不能和已有的函数名重复
  函数名称只能包含字符.数字和下划线
  函数名称不能以数组开始

PHP可通过调用函数的值,找到要调用的函数名,这种函数类型被称为变量函数

声明支持可变参数数量的函数:
function var_args() {
    echo 'Number of parameters:';        
    echo func_num_args();                 //输出传入参数个数
    echo '<br />';
    $args=fun_get_args();                 //返回参数数组
    foreach ($args as $arg){              //数组args的元素赋值给变量$arg
      echo $arg.'<br />';                   //输出变量$arg
   }
}
也可以用fun_get_arg()函数逐个访问参数,该函数参数为参数列表的索引值(参数索引值从0开始)

global关键词用来指定一个在函数中定义或使用的变量具有全局作用域
"&$value"按值引用,引用变量$value.和引用变量时有区别的

使用递归和循环将字符串倒序
  1. <?php
  2. function reverse_r($str){                                //定义函数
  3.         if(strlen($str)>0){                                 //如果取得的字符串长度大于0,往下执行
  4.                 reverse_r(substr($str,1));              /*返回字符串第1个字符后的字符,取出顺序是ello,llo,lo,o,加上本身$str的值一共有5个,递归牵扯个回溯,得出来的值存在不同的空间内要一层一层回溯回去,所以输出的时候有点类似出栈这个原理,先入后出*/
  5.         }
  6.         echo substr($str,0,1);                           //把栈内的字符串出栈,每次取第1个字符,遵循先入后出的原则就反向输出了
  7.         return;
  8. }

  9. function reverse_i($str){
  10.         for($i=1;$i<=strlen($str);$i++){         //$i小于等于取到的字符长度执行循环
  11.                 echo substr($str,-$i,1);               //循环从字符串末尾取1个字符,取出顺序o,l,l,e,H
  12.         }
  13.         return;
  14. }
  15. reverse_r('Hello');
  16. echo '<br />';
  17. reverse_i('Hello')
  18. ?>
复制代码


输出结果:
olleH
olleH

在闭包函数内部使用全局作用域的变量
  1. <?php
  2. $printer=function($value){           //闭包函数是没有名字的,把闭包函数传递给一个变量
  3.         echo "$value <br />";       
  4. };

  5. $products=['Tires'=>100,            
  6.            'Oil'=>10,
  7.                    'Spark Plugs'=>4];       //数组的键名对应键值
  8.                   
  9. $markup=0.20;                       //变量赋值
  10. $apply=function(&$val)use($markup){  //闭包函数引用数组的键值并捕获变量的值,引用可以改变数组的值这里use是捕获变量$markup的值
  11.         $val=$val*(1+$markup);
  12. };       
  13. array_walk($products,$apply);        //array_walk()对参数1使用自定义函数
  14. array_walk($products,$printer);      //array_walk()对参数1使用自定义函数          
  15. ?>
复制代码

输出结果:
120
12
4.8

闭包函数可以调用全局变量,我们知道一般的函数时无法使用函数体外的变量的.还一个闭包函数没有名字并且可以赋值给一个变量
回复

使用道具 举报

8

主题

135

帖子

3270

积分

超级月卡

Rank: 7Rank: 7Rank: 7

积分
3270
 楼主| 发表于 2020-9-7 21:23:16 | 显示全部楼层
本帖最后由 why 于 2020-9-10 10:04 编辑

从世界观的角度可以认为:面向对象的基本哲学是认为世界是由各种各样具有自己的运动规律和内部状态的对象所组成的;不同对象之间的相互作用和通讯构成了完整的现实世界。因此,人们应当按照现实世界这个本来面貌来理解世界,直接通过对象及其相互关系来反映世界。这样建立起来的系统才能符合现实世界的本来面目。
从方法学的角度可以认为:面向对象的方法是面向对象的世界观在开发方法中的直接运用。它强调系统的结构应该直接与现实世界的结构相对应,应该围绕现实世界中的对象来构造系统,而不是围绕功能来构造系统。
面向对象:"Object Oriented"
               Object:      n.        物体; 物品; 东西; (极欲得到、研究、注意等的) 对象; 宗旨; 目的; 目标;
                               v.        不同意; 不赞成; 反对; 提出…作为反对的理由; 抗辩说;
               Oriented:   v.        朝向; 面对; 确定方向; 使适应; 确定方位; 认识方向; 熟悉; 适应;

从哲学层面来讲,现实世界中你作为一个独立的个体,区别于其他客体.你作为一切事务的主体,用观察的眼光去看待客体,所有除你以外的都属于客体,我们把客体不断分类细化,便于我们进行观察一个单一并且唯一的客体.面向对象的编程理念是建立在这种哲学层面的角度构建的,世界是由不同类型的对象构建的,把对象进行分类,对这一类对象再以属性进行分类,抽离出这一类对象的共性,作为基础,这个基础共性适用于这一类对象,这是继承.这一类对象的不同属性用来增加单一客体的唯一性,这是对象属性,属性可以用来进行修改,以确定单一客体的唯一辩识性.
面向对象是面向研究对象,面向对象干嘛?面向对象才能看到对象,看到对象才能更好的研究,研究什么?研究问题的共性,剥离共性解决哪些参差不齐的不同点,用属性来加以标识细化处理,单个解决.


以下内容转载至:https://www.cnblogs.com/net2012/archive/2013/04/03/2997280.html
1.面向对象的概念
面向对象编程(Object Oriented Programming, OOP, 面向对象程序设计)是一种计算机编程架构,OOP 的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而成,OOP达到了软件工程的三个目标:重用性、灵活性和扩展性。为了实现整体运算,每个对象都能够接收信息、处理数据和向其它对象发送信息。面向对象一直是软件开发领域内比较热门的话题,首先,面向对象符合人类看待事物的一般规律。其次,采用面向对象方法可以使系统各部分各司其职、各尽所能。为编程人员敞开了一扇大门,使其编程的代码更简洁、更易于维护,并且具有更强的可重用性。有人说PHP 不是一个真正的面向对象的语言,这是事实。PHP 是一个混合型语言,你可以使用OOP,也可以使用传统的过程化编程。然而,对于大型项目,你可能需要在PHP 中使用纯的OOP去声明类,而且在你的项目里只用对象和类。这个概念我先不多说了,因为有很多朋友远离面向对象编程的主要原因就是一接触面向对象概念的时候就理解不上去, 所以就不想去学下去了。等读者看完整篇内容后再去把概念搞明白吧。


2.什么是类,什么是对象,类和对象之间的关系
类的概念:类是具有相同属性和服务的一组对象的集合。它为属于该类的所有对象提供了统一的抽象描述,其内部包括属性和服务两个主要部分。在面向对象的编程语言中,类是一个独立的程序单位,它应该有一个类名并包括属性说明和服务说明两个主要部分。
对象的概念:对象是系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位。一个对象由一组属性和对这组属性进行操作的一组服务组成。从更抽象的角度来说,对象是问题域或实现域中某些事物的一个抽象,它反映该事物在系统中需要保存的信息和发挥的作用;它是一组属性和有权对这些属性进行操作的一组服务的封装体。客观世界是由对象和对象之间的联系组成的。
类与对象的关系就如模具和铸件的关系,类的实例化结果就是对象,而对一类对象的抽象就是类。类描述了一组有相同特性(属性)和相同行为(方法)的对象。


上面大概就是它们的定义吧,也许你是刚接触面向对象的朋友, 不要被概念的东西搞晕了,给你举个例子吧,如果你去中关村想买几台组装的PC 机,到了那里你第一步要干什么,是不是装机的工程师和你坐在一起,按你提供的信息和你一起完成一个装机的配置单呀,这个配置单就可以想象成是类,它就是一张纸,但是它上面记录了你要买的PC 机的信息,如果用这个配置单买10 台机器,那么这10 台机子,都是按这个配置单组成的,所以说这10 台机子是一个类型的,也可以说是一类的。那么什么是对象呢,类的实例化结果就是对象,用这个配置单配置出来(实例化出来)的机子就是对象,是我们可以操作的实体,10 台机子,10 个对象。每台机子都是独立的,只能说明他们是同一类的,对其中一个机做任何动作都不会影响其它9 台机器,但是我对类修改,也就是在这个配置单上加一个或少一个配件,那么装出来的9 个机子都改变了,这是类和对象的关系(类的实例化结果就是对象)。


3.什么是面向对象编程呢?
就不说他的概念,如果你想建立一个电脑教室,首先要有一个房间, 房间里面要有N 台电脑,有N 张桌子, N 把椅子, 白板, 投影机等等,这些是什么,刚才咱们说了,这就是对象,能看到的一个个的实体,可以说这个电脑教室的单位就是这一个个的实体对象, 它们共同组成了这个电脑教室,那么我们是做程序,这和面向对象有什么关系呢?开发一个系统程序和建一个电脑教室类似,你把每个独立的功能模块抽象成类,形成对象,由多个对象组成这个系统,这些对象之间都能够接收信息、处理数据和向其它对象发送信息等等相互作用。就构成了面向对象的程序。

4.如何抽象出一个类?
上面已经介绍过了,面向对象程序的单位就是对象,但对象又是通过类的实例化出来的,所以我们首先要做的就是如何来声明类,做出来一个类很容易,只要掌握基本的程序语法定义规则就可以做的出来,那么难点在那里呢?一个项目要用到多少个类,用多少个对象,在那要定义类,定义一个什么样的类,这个类实例化出多少个对象,类里面有多少个属性,有多少个方法等等,这就需要读者通过在实际的开发中就实际问题分析设计和总结了。

类的定义:
class 类名{
}
使用一个关键字class 和后面加上一个你想要的类名以及加上一对大括号, 这样一个类的结构就定义出来了,只要在里面写代码就可以了,但是里面写什么?能写什么?怎样写才是一个完整的类呢?上面讲过来,使用类是为了让它实例出对象来给我们用,这就要知道你想要的是什么样的对象了,像上面我们讲的一个装机配置单上写什么,你装出来的机子就有什么。比如说,一个人就是一个对象,你怎么把一个你看好的人推荐给你们领导呢?当然是越详细越好了:
首先,你会介绍这个人姓名、性别、年龄、身高、体重、电话、家庭住址等等。然后,你要介绍这个人能做什么,可以开车,会说英语,可以使用电脑等等。只要你介绍多一点,别人对这个人就多一点了解,这就是我们对一个人的描述, 现在我们总结一下,所有的对象我们用类去描述都是类似的,从上面人的描述可以看到, 做出一个类来,从定义的角度分两部分,第一是从静态上描述,第二是从动态上描述, 静态上的描述就是我们所说的属性,像上面我们看到的,人的姓名、性别、年龄、身高、体重、电话、家庭住址等等。动态上也就是人的这个对象的功能,比如这个人可以开车,会说英语,可以使用电脑等等,抽象成程序时,我们把动态的写成函数或者说是方法,函数和方法是一样的。所以,所有类都是从属性和方法这两方面去写, 属性又叫做这个类的成员属性,方法叫做这个类的成员方法。
class 人{
成员属性:姓名、性别、年龄、身高、体重、电话、家庭住址
成员方法:可以开车, 会说英语, 可以使用电脑
}
属性:
通过在类定义中使用关键字" var "来声明变量,即创建了类的属性,虽然在声明成员属性的时候可以给定初始值, 但是在声明类的时候给成员属性初始值是没有必要的,比如说要是把人的姓名赋上“张三”,那么用这个类实例出几十个人,这几十个人都叫张三了,所以
没有必要, 我们在实例出对象后给成员属性初始值就可以了。
如: var $somevar;
方法(成员函数):
通过在类定义中声明函数,即创建了类的方法。
如: function somefun(参数列表)
{ ... ... }
<?php
class Person
{
//下面是人的成员属性
var $name; //人的名字
var $sex; //人的性别
var $age; //人的年龄
//下面是人的成员方法
function say() //这个人可以说话的方法
{
echo "这个人在说话";
}f
unction run() //这个人可以走路的方法
{
echo "这个人在走路";
}
}
?>
上面就是一个类的声明,从属性和方法上声明出来的一个类,但是成员属性最好在声明的时候不要给初始的值,因为我们做的人这个类是一个描述信息,将来用它实例化对象,比如实例化出来10 个人对象,那么这10 个人, 每一个人的名字、性别、年龄都是不一样的,所以最好不要在这个地方给成员属性赋初值,而是对每个对象分别赋值的。用同样的办法可以做出你想要的类了,只要你能用属性和方法能描述出来的实体都可以定义成类,去实例化对象。为了加强你对类的理解,我们再做一个类,做一个形状的类,形状的范围广了点, 我们就做个矩形吧,先分析一下,想一想从两方面分析,矩形的属性都有什么?矩形的功能都有什么?
class 矩形
{
//矩形的属性
矩形的长;
矩形的宽;
//矩形的方法
矩形的周长;
矩形的面积;
}
<?php
class Rect
{
var $kuan;
var $gao;
function zhouChang()
{
计算矩形的周长;
}f
unction mianJi()
{
计算矩形的面积;
}
}
?>
如果用这个类来创建出多个矩形对象,每个矩形对象都有自己的长和宽, 都可以求出自己的周长和面积了。
类的声明我们就到这里吧!!

5.如何实例化对象
我们上面说过面向对象程序的单位就是对象,但对象又是通过类的实例化出来的,既然我们类会声明了,下一步就是实例化对象了。当定义好类后,我们使用new 关键字来生成一个对象。
$对象名称= new 类名称();
<?php
class Person
{
//下面是人的成员属性
var $name; //人的名字
var $sex; //人的性别
var $age; //人的年龄
//下面是人的成员方法
function say() //这个人可以说话的方法
{
echo "这个人在说话";
}f
unction run() //这个人可以走路的方法
{
echo "这个人在走路";
}
}
$p1=new Person();
$p2=new Person();
$p3=new Person();
?>
$p1=new Person();
这条代码就是通过类产生实例对象的过程,$p1 就是我们实例出来的对象名称,同理,$p2, $p3也是我们实例出来的对象名称,一个类可以实例出多个对象,每个对象都是独立的,上面的代码相当于实例出来3 个人来,每个人之间是没有联系的,只能说明他们都是人类,每个人都有自己的姓名,性别和年龄的属性,每个人都有说话和走路的方法,只要是类里面体现出来的成员属性和成员方法,实例化出来的对象里面就包含了这些属性和方法。对像在PHP 里面和整型、浮点型一样,也是一种数据类,都是存储不同类型数据用的,在运行的时候都要加载到内存中去用, 那么对象在内存里面是怎么体现的呢?内存从逻辑上说大体上是分为4 段,栈空间段、堆空间段、代码段、初始化静态段,程序里面不同的声明放在不同的内存段里面,栈空间段是存储占用相同空间长度并且占用空间小的数据类型的地方,比如说整型1,10,100,1000,10000,100000 等等,在内存里面占用空间是等长的,都是64 位4 个字节。那么数据长度不定长,而且占有空间很大的数据类型的数据放在那内存的那个段里面呢?这样的数据是放在堆内存里面的。栈内存是可以直接存取的,而堆内存是不可以直接存取的内存。对于我们的对象来数就是一种大的数据类型而且是占用空间不定长的类型,所以说对象是放在堆里面的,但对象名称是放在栈里面的,这样通过对象名称就可以使用对象了。
$p1=new Person();
对于这个条代码, $p1 是对象名称在栈内存里面,new Person()是真正的对象是在堆内存里面的,具体的请看下图:从上图可以看出$p1=new Person();等号右边是真正的对象实例,在堆内存里面的实体,上图一共有3 次new Person(),所以会在堆里面开辟3 个空间,产生3 个实例对象,每个对象之间都是相互独立的,使用自己的空间,在PHP 里面,只要有一个new 这个关键字出现就会实例化出来一个对象,在堆里面开辟一块自己的空间。每个在堆里面的实例对象是存储属性的,比如说,现在堆里面的实例对象里面都存有姓名、性别和年龄。每个属性又都有一个地址。
$p1=new Person();等号的右边$p1 是一个引用变量,通过赋值运算符“=”把对象的首地址赋给“$p1”这个引用变量,所以$p1 是存储对象首地址的变量,$p1 放在栈内存里边,$p1 相当于一个指针指向堆里面的对象,所以我们可以通过$p1 这个引用变量来操作对象,通常我们也称对象引用为对象。
6.如何去使用对象中的成员
上面看到PHP 对象中的成员有两种一种是成员属性,一种是成员方法。对象我们以经可以声明了,$p1=new Person();怎么去使用对象的成员呢?要想访问对象中的成员就要使用一个特殊的操
作符“->”来完成对象成员的访问:
对象->属性$p1->name; $p2->age; $p3->sex;
对象->方法$p1->say(); $p2->run();
如下面实例:
<?php
class Person
{
//下面是人的成员属性
var $name; //人的名字
var $sex; //人的性别
var $age; //人的年龄
//下面是人的成员方法
function say() //这个人可以说话的方法
{
echo "这个人在说话";
}f
unction run() //这个人可以走路的方法
{
echo "这个人在走路";
}
}
$p1=new Person(); //创建实例对象$p1
$p2=new Person(); //创建实例对象$p2
$p3=new Person(); //创建实例对象$p3
//下面三行是给$p1对象属性赋值
$p1->name=”张三”;
$p1->sex=”男”;
$p1->age=20;
//下面三行是访问$p1对象的属性
echo “p1对象的名字是:”.$p1->name.”<br>”;
echo “p1对象的性别是:”.$p1->sex.”<br>”;
echo “p1对象的年龄是:”.$p1->age.”<br>”;
//下面两行访问$p1对象中的方法
$p1->say();
$p1->run();
//下面三行是给$p2对象属性赋值
$p2->name=”李四”;
$p2->sex=”女”;
$p2->age=30;
//下面三行是访问$p2对象的属性
echo “p2对象的名字是:”.$p2->name.”<br>”;
echo “p2对象的性别是:”.$p2->sex.”<br>”;
echo “p2对象的年龄是:”.$p2->age.”<br>”;
//下面两行访问$p2对象中的方法
$p2->say();
$p2->run();
//下面三行是给$p3对象属性赋值
$p3->name=”王五”;
$p3->sex=”男”;
$p3->age=40;
//下面三行是访问$p3对象的属性
echo “p3对象的名字是:”.$p3->name.”<br>”;
echo “p3对象的性别是:”.$p3->sex.”<br>”;
LAMP 大讲堂PHP 面向对象技术(全面讲解)
echo “p3对象的年龄是:”.$p3->age.”<br>”;
//下面两行访问$p3对象中的方法
$p3->say();
$p3->run();
?>
从上例中可以看出只是对象里面的成员就要使用对象->属性、对象->方法形式访问,再没有第
二种方法来访问对象中的成员了

7.特殊的引用“$this”的使用
现在我们知道了如何访问对象中的成员,是通过“对象->成员”的方式访问的,这是在对象的外部去访问对象中成员的形式,那么如果我想在对象的内部,让对象里的方法访问本对象的属性,或是对象中的方法去调用本对象的其它方法这时我们怎么办?因为对象里面的所有的成员都要用对象来调用,包括对象的内部成员之间的调用,所以在PHP 里面给我提供了一个本对象的引用$this,每个对象里面都有一个对象的引用$this 来代表这个对象,完成对象内部成员的调用, this 的本意就是“这个”的意思,上面的实例里面,我们实例化三个实例对象$P1、$P2、$P3,这三个对象里面各自存在一个$this 分别代表对象$p1、$p2、$p3 。
通过上图我们可以看到,$this 就是对象内部代表这个对象的引用,在对象内部和调用本对象的成员和对象外部调用对象的成员所使用的方式是一样的。
$this->属性$this->name; $this->age; $this->sex;
$this->方法$this->say(); $this->run();
修改一下上面的实例,让每个人都说出自己的名字,性别和年龄:
<?php
class Person
{
//下面是人的成员属性
var $name; //人的名字
var $sex; //人的性别
var $age; //人的年龄
//下面是人的成员方法
function say() //这个人可以说话的方法
{
echo "我的名字叫:".$this->name." 性别:".$this->sex." 我的年龄是:
".$this->age."<br>";
}f
unction run() //这个人可以走路的方法
{
echo "这个人在走路";
}
}
$p1=new Person(); //创建实例对象$p1
$p2=new Person(); //创建实例对象$p2
$p3=new Person(); //创建实例对象$p3
//下面三行是给$p1对象属性赋值
$p1->name="张三";
$p1->sex="男";
$p1->age=20;
//下面访问$p1对象中的说话方法
$p1->say();
//下面三行是给$p2对象属性赋值
$p2->name="李四";
$p2->sex="女";
$p2->age=30;
//下面访问$p2对象中的说话方法
$p2->say();
//下面三行是给$p3对象属性赋值
$p3->name="王五";
$p3->sex="男";
$p3->age=40;
//下面访问$p3对象中的说话方法
$p3->say();
?>
输出结果为:
我的名字叫:张三性别:男我的年龄是:20
我的名字叫:李四性别:女我的年龄是:30
我的名字叫:王五性别:男我的年龄是:40
分析一下这个方法:
function say() //这个人可以说话的方法
{
echo "我的名字叫:".$this->name." 性别:".$this->sex." 我的年龄是:
".$this->age."<br>";
}
在$p1、$p2 和$p3 这三个对象中都有say()这个方法,$this 分别代表这三个对象, 调用相应的属性,打印出属性的值,这就是在对象内部访问对象属性的方式, 如果相在say()这个方法里调用run()这个方法也是可以的,在say()这个方法中使用$this->run()的方式来完成调用。
8.构造方法与析构方法
大多数类都有一种称为构造函数的特殊方法。当创建一个对象时,它将自动调用构造函数,也就是使用new 这个关键字来实例化对象的时候自动调用构造方法。构造函数的声明与其它操作的声明一样,只是其名称必须是__construct( )。这是PHP5 中的变化,以前的版本中,构造函数的名称必须与类名相同,这种在PHP5 中仍然可以用,但现在以经很少有人用了,这样做的好处是可以使构造函数独立于类名,当类名发生改变时不需要改相应的构造函数名称了。为了向下兼容,如果一个类中没有名为__construct( )的方法,PHP 将搜索一个php4 中的写法,与类名相同名的构造方法。格式:function __construct ( [参数] ) { ... ... }
在一个类中只能声明一个构造方法,而是只有在每次创建对象的时候都会去调用一次构造方法,不能主动的调用这个方法,所以通常用它执行一些有用的初始化任务。比如对成属性在创建对象的时候赋初值。
<?
//创建一个人类
class Person
{
//下面是人的成员属性
var $name; //人的名字
var $sex; //人的性别
var $age; //人的年龄
//定义一个构造方法参数为姓名$name、性别$sex和年龄$age
function __construct($name, $sex, $age)
{
//通过构造方法传进来的$name给成员属性$this->name赋初使值
$this->name=$name;
//通过构造方法传进来的$sex给成员属性$this->sex赋初使值
$this->sex=$sex;
//通过构造方法传进来的$age给成员属性$this->age赋初使值
$this->age=$age;
}/
/这个人的说话方法
function say()
{
echo "我的名字叫:".$this->name." 性别:".$this->sex." 我的年龄是:
".$this->age."<br>";
}
}
//通过构造方法创建3个对象$p1、p2、$p3,分别传入三个不同的实参为姓名、性别和年龄
$p1=new Person(“张三”,”男”, 20);
$p2=new Person(“李四”,”女”, 30);
$p3=new Person(“王五”,”男”, 40);
//下面访问$p1对象中的说话方法
$p1->say();
//下面访问$p2对象中的说话方法
$p2->say();
//下面访问$p3对象中的说话方法
$p3->say();
?>
输出结果为:
我的名字叫:张三性别:男我的年龄是 : 20
我的名字叫:李四性别:女我的年龄是 : 30
我的名字叫:王五性别:男我的年龄是 : 40
如图:
析构函数:
与构造函数相对的就是析构函数。析构函数是PHP5 新添加的内容,在PHP4 中没有析构函数。析构函数允许在销毁一个类之前执行的一些操作或完成一些功能,比如说关闭文件,释放结果集等,析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行,也就是对象在内存中被销毁前调用析构函数。与构造函数的名称类似,一个类的析构函数名称必须是__destruct( )。析构函数不能带有任何参数。
格式:function __destruct ( ) { ... ... }
<?
//创建一个人类
class Person
{
//下面是人的成员属性
var $name; //人的名字
var $sex; //人的性别
var $age; //人的年龄
//定义一个构造方法参数为姓名$name、性别$sex和年龄$age
function __construct($name, $sex, $age)
{
//通过构造方法传进来的$name给成员属性$this->name赋初使值
$this->name=$name;
//通过构造方法传进来的$sex给成员属性$this->sex赋初使值
$this->sex=$sex;
//通过构造方法传进来的$age给成员属性$this->age赋初使值
$this->age=$age;
}
//这个人的说话方法
function say()
{
echo "我的名字叫:".$this->name." 性别:".$this->sex." 我的年龄是:
".$this->age."<br>";
}
//这是一个析构函数,在对象销毁前调用
function __destruct()
{
echo “再见”.$this->name.”<br>”;
}
//通过构造方法创建3个对象$p1、p2、$p3,分别传入三个不同的实参为姓名、性别和年龄
$p1=new Person(“张三”,”男”, 20);
$p2=new Person(“李四”,”女”, 30);
$p3=new Person(“王五”,”男”, 40);
//下面访问$p1对象中的说话方法
$p1->say();
//下面访问$p2对象中的说话方法
$p2->say();
//下面访问$p3对象中的说话方法
$p3->say();
?>
输出结果为:
我的名字叫:张三性别:男我的年龄是:20
我的名字叫:李四性别:女我的年龄是:30
我的名字叫:王五性别:男我的年龄是:40
再见张三
再见李四
再见王五

9.封装性
封装性是面向对象编程中的三大特性之一,封装性就是把对象的属性和服务结合成一个独立的相同单位,并尽可能隐蔽对象的内部细节,包含两个含义:1.把对象的全部属性和全部服务结合在一起,形成一个不可分割的独立单位(即对象)。2.信息隐蔽,即尽可能隐蔽对象的内部细节,对外形成一个边界〔或者说形成一道屏障〕,只保留有限的对外接口使之与外部发生联系。封装的原则在软件上的反映是:要求使对象以外的部分不能随意存取对象的内部数据(属性),从而有效的避免了外部错误对它的"交叉感染",使软件错误能够局部化,大大减少查错和排错的难度。
用个实例来说明吧,假如某个人的对象中有年龄和工资等属性,像这样个人隐私的属性是不想让其它人随意就能获得到的,如果你不使用封装,那么别人想知道就能得到,但是如果你封装上之后别人就没有办法获得封装的属性,除非你自己把它说出去,否则别人没有办法得到。

再比如说,个人电脑都有一个密码,不想让其它人随意的登陆,在你的电脑里面拷贝和粘贴。还有就是像人这个对象,身高和年龄的属性,只能是自己来增长,不可以让别人随意的赋值等等。使用private 这个关键字来对属性和方法进行封装:
原来的成员:
var $name; //声明人的姓名
var $sex; //声明人的性别
var $age; //声明人的年龄
function run(){… … .}
改成封装的形式:
private $name; //把人的姓名使用private 关键字进行封装
private $sex; //把人的性别使用private 关键字进行封装
private $age; //把人的年龄使用private 关键字进行封装
private function run(){… … } //把人的走路方法使用private 关键字进行封装
注意:只要是成员属性前面有其它的关键字就要去掉原有的关键字“var”。通过private 就可以把人的成员(成员属性和成员方法)封装上了。封装上的成员就不能被类外面直接访问了,只有对象内部自己可以访问;下面的代码会产生错误:
class Person
{
//下面是人的成员属性
private $name; //人的名字,被private封装上了
private $sex; //人的性别, 被private封装上了
private $age; //人的年龄, 被private封装上了
//这个人可以说话的方法
function say()
{
echo "我的名字叫:".$this->name." 性别:".$this->sex." 我的年龄是:
".$this->age."<br>";
}/
/这个人可以走路的方法, 被private封装上了
private function run()
{
echo "这个人在走路";
}
}
//实例化一个人的实例对象
$p1=new Person();
//试图去给私有的属性赋值, 结果会发生错误
$p1->name="张三";
$p1->sex="男";
$p1->age=20;
//试图去打印私有的属性, 结果会发生错误
echo $p1->name.”<br>”;
echo $p1->sex.”<br>”;
echo $p1->age.”<br>”
//试图去打印私有的成员方法, 结果会发生错误
$p1->run();
输出结果为:
Fatal error: Cannot access private property Person : : $name
Fatal error: Cannot access private property Person : : $sex
Fatal error: Cannot access private property Person : : $age
Fatal error: Cannot access private property Person : : $name
Fatal error: Call to private method Person : : run() from context ''
从上面的实例可以看到,私有的成员是不能被外部访问的,因为私有成员只能在本对象内部自己访问,比如,$p1 这个对象自己想把他的私有属性说出去,在say()这个方法里面访问了私有属性,这样是可以。(没有加任何访问控制,默认的是public 的,任何地方都可以访问)
//这个人可以说话的方法, 说出自己的私有属性,在这里也可以访问私有方法
function say()
{
echo "我的名字叫:".$this->name." 性别:".$this->sex." 我的年龄是:
".$this->age."<br>";
//在这里也可以访问私有方法
//$this->run();
}
因为成员方法say()是公有的, 所以我们在类的外部调用say()方法是可以的,改变上面的代码;
class Person
{
//下面是人的成员属性
private $name; //人的名字,被private封装上了
private $sex; //人的性别, 被private封装上了
private $age; //人的年龄, 被private封装上了
//定义一个构造方法参数为私有的属性姓名$name、性别$sex和年龄$age进行赋值
function __construct($name, $sex, $age)
{
//通过构造方法传进来的$name给私有成员属性$this->name赋初使值
$this->name=$name;
//通过构造方法传进来的$sex给私有成员属性$this->sex赋初使值
$this->sex=$sex;
//通过构造方法传进来的$age给私有成员属性$this->age赋初使值
$this->age=$age;
}/
/这个人可以说话的方法, 说出自己的私有属性,在这里也可以访问私有方法
function say()
{
echo "我的名字叫:".$this->name." 性别:".$this->sex." 我的年龄是:
".$this->age."<br>";
}
}
//通过构造方法创建3个对象$p1、p2、$p3,分别传入三个不同的实参为姓名、性别和年龄
$p1=new Person(“张三”,”男”, 20);
$p2=new Person(“李四”,”女”, 30);
$p3=new Person(“王五”,”男”, 40);
//下面访问$p1对象中的说话方法
$p1->say();
//下面访问$p2对象中的说话方法
$p2->say();
//下面访问$p3对象中的说话方法
$p3->say();
输出结果为:
我的名字叫:张三性别:男我的年龄是:20
我的名字叫:李四性别:女我的年龄是:30
我的名字叫:王五性别:男我的年龄是:40
因为构造方法是默认的公有方法(构造方法不要设置成私有的),所以在类的外面可以访问到,这样就可以使用构造方法创建对象, 另外构造方法也是类里面的函数,所以可以用构造方法给私有的属性赋初值。Say()的方法是默认公有的, 所以在外面也可以访问的到, 说出他自己的私有属性。
从上面的例子中我们可以看到,私有的成员只能在类的内部使用,不能被类外部直接来存取,但是在类的内部是有权限访问的,所以有时候我们需要在类的外面给私有属性赋值和读取出来,也就是给类的外部提供一些可以存取的接口,上例中构造方法就是一种赋值的形式,但是构造方法只是在创建对象的时候赋值,如果我们已经有一个存在的对象了,想对这个存在的对象赋值,这个时候,如果你还使用构造方法传值的形式传值,那么就创建了一个新的对象,并不是这个已存在的对象了。所以我们要对私有的属性做一些可以被外部存取的接口,目的就是可以在对象存在的情况下,改变和存取属性的值,但要注意,只有需要让外部改变的属性才这样做,不想让外面访问的属性是不做这样的接口的,这样就能达到封装的目的,所有的功能都是对象自己来完成,给外面提供尽量少的操作。
如果给类外部提供接口,可以为私有属性在类外部提供设置方法和获取方法,来操作私有属性.
例如:
prvate $age; //私有的属性年龄
function setAge($age) //为外部提供一个公有设置年龄的方法
{
if($age<0 || $age>130) //在给属性赋值的时候,为了避免非法值设置给属性
return;
$this->age=$age;
}f
unction getAge() //为外部提供一个公有获取年龄的方法
{
return($this->age);
}
上面的方法是为一个成员属性设置和获取值, 当然你也可以为每个属性用同样的方法对其进行赋值和取值的操作,完成在类外部的存取工作。
10.__set() __get() __isset() __unset()四个方法的应用
一般来说,总是把类的属性定义为private,这更符合现实的逻辑。但是,对属性的读取和赋值操作是非常频繁的,因此在PHP5 中,预定义了两个函数“__get()”和“__set()”来获取和赋值其属性,以及检查属性的“__isset()”和删除属性的方法“__unset()”。
上一节中,我们为每个属性做了设置和获取的方法,在PHP5 中给我们提供了专门为属性设置值和获取值的方法,“__set()”和“__get()”这两个方法,这两个方法不是默认存在的,而是我们手工添加到类里面去的,像构造方法(__construct())一样, 类里面添加了才会存在,可以按下面的方式
来添加这两个方法,当然也可以按个人的风格来添加:
//__get()方法用来获取私有属性
private function __get($property_name)
{
if(isset($this->$property_name))
{
return($this->$property_name);
}else
{
return(NULL);
}
}/
/__set()方法用来设置私有属性
private function __set($property_name, $value)
{
$this->$property_name = $value;
}
__get()方法:这个方法用来获取私有成员属性值的,有一个参数,参数传入你要获取的成员属性的名称,返回获取的属性值,这个方法不用我们手工的去调用,因为我们也可以把这个方法做成私有的方法,是在直接获取私有属性的时候对象自动调用的。因为私有属性已经被封装上了,是不能直接获取值的(比如:“echo $p1->name”这样直接获取是错误的),但是如果你在类里面加上了这个方法,在使用“echo $p1->name”这样的语句直接获取值的时候就会自动调用__get($property_name)方法,将属性name 传给参数$property_name,通过这个方法的内部执行,返回我们传入的私有属性的值。如果成员属性不封装成私有的,对象本身就不会去自动调用这个方法。
__set()方法:这个方法用来为私有成员属性设置值的,有两个参数,第一个参数为你要为设置值的属性名,第二个参数是要给属性设置的值,没有返回值。这个方法同样不用我们手工去调用,
它也可以做成私有的,是在直接设置私有属性值的时候自动调用的,同样属性私有的已经被封装上了, 如果没有__set()这个方法,是不允许的, 比如:$this->name=‘zhangsan’, 这样会出错,但是如果你在类里面加上了__set($property_name, $value)这个方法,在直接给私有属性赋值的时候,就会自动调用它,把属性比如name 传给$property_name, 把要赋的值“zhangsan”传给$value,通过这个方法的执行,达到赋值的目的。如果成员属性不封装成私有的,对象本身就不会去自动调用这
个方法。为了不传入非法的值, 还可以在这个方法给做一下判断。代码如下:
<?php
class Person
{
//下面是人的成员属性, 都是封装的私有成员
private $name; //人的名字
private $sex; //人的性别
private $age; //人的年龄
//__get()方法用来获取私有属性
private function __get($property_name)
{
echo "在直接获取私有属性值的时候,自动调用了这个__get()方法<br>";
if(isset($this->$property_name))
{
return($this->$property_name);
}e
lse
{
return(NULL);
}
}/
/__set()方法用来设置私有属性
private function __set($property_name, $value)
{
echo "在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值<br>";
$this->$property_name = $value;
}
}
$p1=new Person();
//直接为私有属性赋值的操作, 会自动调用__set()方法进行赋值
$p1->name="张三";
$p1->sex="男";
$p1->age=20;
//直接获取私有属性的值, 会自动调用__get()方法,返回成员属性的值
echo "姓名:".$p1->name."<br>";
echo "性别:".$p1->sex."<br>";
echo "年龄:".$p1->age."<br>";
?>
程序执行结果:
在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值
在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值
在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值
在直接获取私有属性值的时候,自动调用了这个__get()方法
姓名:张三
在直接获取私有属性值的时候,自动调用了这个__get()方法
性别:男
在直接获取私有属性值的时候,自动调用了这个__get()方法
年龄:20
以上代码如果不加上__get()和__set()方法,程序就会出错,因为不能在类的外部操作私有成员,而上面的代码是通过自动调用__get()和__set()方法来帮助我们直接存取封装的私有成员的。__isset() 方法:在看这个方法之前我们看一下“isset()”函数的应用,isset()是测定变量是否设定用的函数,传入一个变量作为参数,如果传入的变量存在则传回true,否则传回false。那么如果在一个对象外面使用“isset()”这个函数去测定对象里面的成员是否被设定可不可以用它呢?分两种情况,如果对象里面成员是公有的,我们就可以使用这个函数来测定成员属性,如果是私有的成员属性,这个函数就不起作用了,原因就是因为私有的被封装了,在外部不可见。那么我们就不可以在对象的外部使用“isset()”函数来测定私有成员属性是否被设定了呢?可以,你只要在类里面加上一个“__isset()”方法就可以了,当在类外部使用”isset()”函数来测定对象里面的私有成员是否被设定时, 就会自动调用类里面的“__isset()”方法了帮我们完成这样的操作,“__isset()”方法也可以做成私有的。你可以在类里面加上下面这样的代码就可以了:
private function __isset($nm)
{
echo "当在类外部使用isset()函数测定私有成员$nm时,自动调用<br>";
return isset($this->$nm);
}
__unset()方法:看这个方法之前呢,我们也先来看一下“unset()”这个函数,“unset()”这个函数的作用是删除指定的变量且传回true,参数为要删除的变量。那么如果在一个对象外部去删除对象内部的成员属性用“unset()”函数可不可以呢,也是分两种情况,如果一个对象里面的成员属性是公有的,就可以使用这个函数在对象外面删除对象的公有属性,如果对象的成员属性是私有的,我使用这个函数就没有权限去删除,但同样如果你在一个对象里面加上“__unset()”这个方法,就可以在对象的外部去删除对象的私有成员属性了。在对象里面加上了“__unset()”这个方法之后,在对象外部使用“unset()”函数删除对象内部的私有成员属性时,自动调用“__unset()”函数来帮我们删除对象内部的私有成员属性,这个方法也可以在类的内部定义成私有的。在对象里面加上下
面的代码就可以了:
private function __unset($nm)
{
echo "当在类外部使用unset()函数来删除私有成员时自动调用的<br>";
unset($this->$nm);
}
我们来看一个完整的实例:
<?php
class Person
{
//下面是人的成员属性
private $name; //人的名字
private $sex; //人的性别
private $age; //人的年龄
//__get()方法用来获取私有属性
private function __get($property_name)
{
if(isset($this->$property_name))
{
return($this->$property_name);
}else {
return(NULL);
}
}/
/__set()方法用来设置私有属性
private function __set($property_name, $value)
{
$this->$property_name = $value;
}/
/__isset()方法
private function __isset($nm)
{
echo "isset()函数测定私有成员时,自动调用<br>";
return isset($this->$nm);
}/
/__unset()方法
private function __unset($nm)
{
echo "当在类外部使用unset()函数来删除私有成员时自动调用的<br>";
unset($this->$nm);
}
}
$p1=new Person();
$p1->name="this is a person name";
//在使用isset()函数测定私有成员时,自动调用__isset()方法帮我们完成,返回结果为true
echo var_dump(isset($p1->name))."<br>";
echo $p1->name."<br>";
//在使用unset()函数删除私有成员时,自动调用__unset()方法帮我们完成,删除name私有属性
unset($p1->name);
//已经被删除了, 所这行不会有输出
echo $p1->name;
?>
输出结果为:
isset()函数测定私有成员时,自动调用
bool(true)
this is a person name
当在类外部使用unset()函数来删除私有成员时自动调用的__set()、__get()、__isset()、__unset() 这四个方法都是我们添加到对象里面的,在需要时自动调用的,来完成在对象外部对对象内部私有属性的操作

以下内容转载至:https://www.cnblogs.com/457248499-qq-com/p/7384839.html
接口(interface)技术
什么是接口?
先看抽象类:

abstract  class  类名  {

属性1;

属性2;

.....

非抽象方法1;

非抽象方法2;

......

抽象方法1;

抽象方法2;

......

}  

设想,将上述抽象类中“实在的成员”,删除,即删除那些非抽象的成员。则,自然该抽象类中,就只有抽象方法;

abstract  class  类名  {

抽象方法1;

抽象方法2;

......

}  

由此,可以理解为:这个抽象类,“太抽象了”,几乎自己什么都没做,就光让别人做什么。



那么:



接口就是这样一个“天然不实在”的家伙:

接口,就是规定,里面只能放“抽象方法”和“常量”的一种类似类的语法结构;

——可见,接口就是“比抽象类更抽象的”一种语法结构。



接口(interface)定义形式:
interface  接口名{

常量1;

常量2;

.....

抽象方法1;

抽象方法2;

.....

}

说明:

1,可见,接口中,只有常量(接口常量)和抽象方法两种成员;

2,接口常量的使用形式为: 接口名称::常量名称;

3,接口中的抽象方法,不要使用abstract修饰,也不需要使用访问控制修饰符,因为其天然就是public

为什么需要接口?
面向对象编程思想是对“现实世界”的描述(模拟)!

现实世界往往都都是多继承的;

但:

出于降低类跟类之间关系的复杂度的考虑,就将语言设计为单继承的;

但这样,就无法表达出现实世界的多继承特性;

则:

接口就是对没有多继承的类之间关系的一个补充;



因为:接口可以实现“多继承”——但此时不称为继承而已,而是称为“实现”;

即:

接口1  -->> 类1;

就称为:类1实现了接口1;

其本质,其实就是类1中,有了接口1中“特征信息”;



使用形式:
形式为:

class  类名  implements  接口名1, 接口名2, ....{

//类的定义。

}

这里,叫做,类实现了接口。

其中,接口跟接口之间,也可以继承,跟类之间的继承:

interface  接口1  extends  接口2{

//接口的成员定义;。。。。

}
类和接口的大总结



以下内容转载至:https://www.cnblogs.com/lixiuran/p/3769879.html

PHP在魔术函数__autoload()方法出现以前,如果你要在一个程序文件中实例化100个对象,那么你必须用include或者require包含进来100个类文件,或者你把这100个类定义在同一个类文件中——相信这个文件一定会非常大。

但是__autoload()方法出来了,以后就不必为此大伤脑筋了,这个类会在你实例化对象之前自动加载制定的文件。

下边我们通过一个例子来看一下,具体的使用方法,并在稍后说明使用PHP魔术函数__autoload应该注意些什么。
代码如下    复制代码

//定义一个类ClassA,文件名为ClassA.php
class ClassA{
public  function __construct(){
  echo "ClassA load success!";
}
}

//定义一个类ClassB,文件名为ClassB.php,ClassB继承ClassA
class ClassB extends ClassA {
public function __construct(){
  //parent::__construct();
  echo "ClassB load success!";
}
}

定义两个测试用的类之后,我们来编写一个含有__autoload()方法的PHP运行程序文件如下:
代码如下    复制代码

function __autoload($classname){
$classpath="./".$classname.'.php';
if(file_exists($classpath)){
  require_once($classpath);
}
else{
  echo 'class file'.$classpath.'not found!';
}
}

$newobj = new ClassA();
$newobj = new ClassB();

这个文件的运行是一点问题都没有的,可见autoload是多么的好用啊,呵呵……
但是不得不提醒你一下几个方面是必须要注意的。

1、如果类存在继承关系(例如:ClassB extends ClassA),并且ClassA不在ClassB所在目录
利用__autoload魔术函数实例化ClassB的时候就会受到一个致命错误:
代码如下    复制代码
Fatal error: Class ‘Classd’ not found in ……ClassB.php on line 2,

解决方法:把所有存在extends关系的类放在同一个文件目录下,或者在实例化一个继承类的时候在文件中手工包含被继承的类;

2、另外一个需要注意的是,类名和类的文件名必须一致,才能更方便的使用魔术函数__autoload;

其他需要注意的事情:
3、在CLI模式下运行PHP脚本的话这个方法无效;

4、如果你的类名称和用户的输入有关——或者依赖于用户的输入,一定要注意检查输入的文件名,例如:.././这样的文件名是非常危险的。










第6章 面向对象特性
我们用句柄(唯一标识符)来标识对象
对象可以按类进行分类.类是表示彼此之间可能互不相同,但是必须具有一些共同点的对象集合.虽然类所包含的对象可能具有不同属性值,但是,这些对象都具有以相同方式实现的相同操作以及表示相同事务的相同属性
面向对象的编程语言必须支持多态性,多态性是指不同类对同一操作可以用不同的行为实现
多态性与其说是对象的特性,不如说是行为的特征.在PHP中,只有类的成员函数可以是多态的
集成允许我们使用子类之间创建层次关系,子类将从它的超类(也叫父类)继承属性和操作.通过继承,我们可以在已有的基础上创建新类.根据实际需要,可以从一个简单的基类开始,派生出更复杂.更专门的类

class关键字用来定义类

如下所示创建一个名为"classname"的类,它具有两个属性$attribute1,$attribute2
class classname
{
  public $attribute1;
  public $attribute2;
}

通过在类定义中声明函数,可以创建类的操作.如下所示的代码创建一个名为classname的类,该类包含两个不执行任何操作的方法,其中operation1()不带参数,而operation2()带有两个参数:
class classname
{
  function operation1()
   {
   }
  function operation2($param1,$param2)
   {
   }  
}

大多数类都有一种称为构造函数的特殊操作.当创建一个对象时,对象的构造函数将被调用.通常这将执行一些有用的初始化任务.如:设置属性的初始值或者创建该对象需要的其他对象
构造函数的声明与其他操作的声明一样,只是其名称必须是_construct().尽管可以手动调用构造函数,但其本意是在创建一个对象时自动调用.如下所示的代码声明了一个具有构造函数的类:
class classname
{
  function _construct($param)
   {
      echo "Constructor called with parameter ".$param."<br />";
    }
}

与构造函数相对的就是析构函数.析构函数允许在销毁一个类之前被调用执行,它将完成一些操作或实现一些功能,这些操作或功能通常在所有对该类的引用都被重置或超出作用域时自动发生
与构造函数的命名类似,一个析构函数名称必须是_destruct().析构函数不能带有任何参数

在声明一个类后,需要创建一个可供使用的对象,它是一个特定的个体,即类的一个成员.这也叫创建一个实例或实例化一个类.可以使用关键词"new"来创建一个对象.需要指定创建的对象是哪一个类的实例,并且为构造函数提供任何所需的参数
如下所示的代码声明了一个具有构造函数,名为classname的类,然后又创建两个classname类型的对象
class classname
{
  function _construct($param)
   {
      echo "Constructor called with parameter ".$param."<br />";
    }
}

$a=new classname("First");
$b=new classname("Second");
由于每次创建一个对象都将调用这个构造函数,以上代码将产生如下所示的输出:
Constructor called with parameter First
Constructor called with parameter Second

在一个类中,可以访问一个特殊的指针---$this.如果当前类的一个属性为$attribute,则当在该类中通过一个操作设置或访问该变量时,可以使用$this->attribute来引用
如下所示的代码说明了如何在一个类中设置和访问属性:
class classname
{
  public $attribute;
  function operation($param)
   {
     $this->attribute=$param;
     echo $this->attribute;
   }
}
是否可以在类外部访问一个属性是由访问修饰符来确定的,这个示例没有对属性设置访问限制,因此可以按照如下所示的方式从类外部该问该属性:
  1. class classname
  2. {
  3.   public $attribute;
  4. }
  5. $a=new classname();
  6. $a->attribute="value";
  7. echo $a->attribute;
复制代码

输出结果:
value


  1. <?php
  2. class classname                      //声明类
  3. {
  4.   public $attribute;                  //声明属性,public关键字用来声明属性
  5.   function operation($param)   //声明函数创建类操作
  6.    {
  7.      $this->attribute=$param;  
  8.      //echo $this->attribute;  引用成功,这里这行注释并不影响返回值
  9.    }
  10. }

  11. $a=new classname();             //创建对象
  12. $a->attribute="value";          //访问类的$attribute,并带回字符串赋值给类属性供函数调用
  13. echo $a->attribute;             //返回类属性
  14. ?>
复制代码

输出结果:
value

可以以调用类属性相同的方法调用类操作,有如下所示类:
class classname
{
  function operation1();
   {
   }
  function operation2($param1,$param2);
   {
   }  
}
创建一个classname类型的对象,命名为$a,如下代码所示:
$a=new classname();
可以按照调用其他函数的方法调用类操作:操作名称以及必要参数.由于这些操作属于一个对象,而不是普通的函数,所以必须执行操作所属的对象.与访问对象属性方法一样,可以通过对象名称及操作名称来访问操作,如下代码所示:
$x=$a->operation1();                      //访问操作方法,返回值赋值给变量x
$y=$a->operation2(12,"test");         //访问操作方法,返回值赋值给变量y

php提供了访问修饰符.它们可以控制属性和方法的可见性.通常访问修饰符放置在属性和方法声明之前.PHP支持如下3中不同的访问修饰符:
   默认选项是public,这意味着如果没有为一个属性或方法指定访问修饰符,它将是public.公有属性方法可以在类的内部或外部进行访问
   private访问修饰符意味着被标记的属性或方法只能在类内部直接进行访问.私有的属性和方法将不会被继承
   protected访问修饰符意味着被标记的属性或方法只能在类内部进行访问,它也存在于任何子类,在这里protected理解成位于private和public之间的关键字
如下所示的代码说明了public和private访问修饰符的使用方法:
class manners
{
  private $greeting="Hello";                //私有
  public function greet($name)            //公有
  {
     echo "$this->greeting, $name";
  }
}

最初版本的访问器函数如下所示:

<?php
class classname                     //声明类
{
  public $attribute;                //属性
  function _get($name)              //创建_get操作
  {
    return $this->$name;
  }
  function _set($name,$value)       //创建_set操作
  {
    $this->$name=$value;
  }
}
$a=new classname();                 //创建$a对象
$a->attribute;                      //访问attribute属性,_get函数对象名attribute
$a->attribute=5;                    //访问attribute属性,_set函数返回对象的值  
?>

要指定一个类称为另一个类的子类,可以使用关键字"extends"
如下代码创建了一个名为B的类,它继承了在它前面定义的类A
class B extends A
{
  public $attribute2;
  function operation2()
  {
  }
}
如果A类如下:
class A
{
  public $attribute1;
  function operation1()
  {
  }
}

如下所示的有对类B的对象的操作和属性的访问都是有效的:
$b=new B();                             //创建B类对象$b
$b->operation1();                     //访问A类属性$attribute1的操作
$b->attribute1=10;                   //访问A类属性$attribute1
$b->operation2();                    //访问B类属性$attribute1的操作
$b->attribute2=10;                  //访问B类属性$attribute1
因为类B继承了类A,所以可以直接访问到类A的属性和操作,尽管这些操作和属性是在类A声明的.作为A的子类,B具有与A一样的功能和数据.此外B还声明了一个字节的的属性和操作
继承是单方向的.子类可以从父类或超类继承特性,但是父类却不能从子类继承特性

可以使用private和protected访问修饰符来控制需要继承的内容.如果一个属性或方法被指定为private,它将不能被继承.如果一个属性或方法被指定为protected,它将在类外部不可见(就像一个private元素),但是可以被继承
  1. <?php
  2. class A
  3. {
  4.         private function operation1()        //私有操作
  5.         {
  6.                 echo "operation1 called";
  7.         }
  8.         protected function operation2()      //protected可以被继承但只能在子类内部使用
  9.         {
  10.                 echo "operation2 called";
  11.         }
  12.         public function operation3()         //公有操作可以在类外部调用
  13.         {
  14.                 echo "operation3 called";
  15.         }
  16. }
  17. class B extends A
  18. {
  19.         function _construct()
  20.         {
  21.                 $this->operation1();
  22.                 $this->operation2();
  23.                 $this->operation3();
  24.         }
  25. }
  26. $b=new B;
  27. $this->operation1();        //错误,私有操作不能在子类中调用
  28. $this->operation2();        //错误,protected可以被继承但只能在子类内部使用
  29. $this->operation3();        //公有操作可以在类外部调用
  30. ?>
复制代码


在子类中,再次声明相同的属性和操作也是有效的,而且在某些情况下这将会是非常有用的.我们可能需要在子类中给某个属性赋予一个与其超类属性值不同的默认值,或者给某个操作赋予一个与其超类操作不同的功能,这就叫覆盖

  1. <?php
  2. class A
  3. {
  4.         public $attribute='default value';
  5.         function operation()
  6.         {
  7.                 echo 'Something<br />';
  8.                 echo 'The value of $attribute is '.$this->attribute.'<br />';
  9.         }
  10. }

  11. class B extends A
  12. {
  13.         public $attribute='different value';
  14.         
  15.         function operation()
  16.         {
  17.                 echo '<br />Something else<br />';
  18.                 echo 'The value of $attribute is '.$this->attribute.'<br />';
  19.                 echo parent::operation();               //调用类A操作
  20.         }
  21. }
  22. $a=new A();
  23. $a->operation();
  24. /*类A的对象调用operation方法,产生如下结果:
  25. Something
  26. The value of $attribute is default value*/

  27. $b=new B();
  28. $b->operation();
  29. /*类B的对象调用operation方法,产生如下结果:
  30. Something else
  31. The value of $attribute is different value
  32. Something                  //输出的这话是因为在类B中调用了类A的operation()操作
  33. The value of $attribute is different value*/
  34. ?>
复制代码


echo parent : : operation(); 调用父类的操作,还可以调用父类的构造函数,对它们进行修改

PHP提供了两种机制来支持类多重继承功能:接口和Trait

接口可以看作是多重继承问题的解决办法,接口的思想是指定一个实现该接口的类必须实现的一系列函数,如需要一系列能够显示自身的类.除了可以定义具有display()函数的父类,同时使这些子类都继承父类并覆盖该方法外,还可以实现一个接口,如下所示:
interface Displayable
{
        function display();
}
class webpage implement Displayable
{
        function display()
        {
                //....
        }
}
以上代码说明了多重继承的一种解决办法,因为webpage类可以继承一个类,同时又可以实现一个或多个接口
如果没有实现接口中指定的方法(在这个实例中是display()方法),将产生一个致命的错误

Trait是能充分利用多重继承又不带来痛苦的方法.在Trait中,可以对将在多个类中重复的功能进行分组.一个类可以组合多个Trait,而Trait可以继承其他Trait.Trait是代码重用的最佳构建模块
接口和Trait最重要的不同就是:Trait包含了实现,而接口则不需要
可以按照创建类的方式创建Trait,但是需要使用Trait关键字,如下代码所示:
Trait logger
{
        public function logmessage($message,$level='DEBUG')
        {
                //write $message to a log
        }
}

使用Trait,需要编写如下代码
class fileStorage
{
        use logger;
        function store($data){
                //...
                $this->logmessage($msg)
        }
如果需要,fileStorage类可以覆盖logmessage()方法.但是,需要注意的是,如果fileStorage类从父类继承了logmessage()方法,在默认情况下,名为logger的Trait将覆盖logmessage()方法.也就是,Trait方法覆盖继承的方法,但当前类方法覆盖了Trait的方法.
Trait的一个优点是可以组合多个Trait,当有多个方法具有相同名称,可以显式地指定需要使用特定Trait的功能.考虑如下所示示例:
  1. <?php
  2. trait filelogger
  3. {
  4.         public function logmessage($message,$level='DEBUG')
  5.         {
  6.                 //wite $message to a log file
  7.         }
  8. }
  9. trait  sysLogger
  10. {
  11.         public function logmessage($message,$level='DEBUG')
  12.         {
  13.                 //wite $message to a log file
  14.         }
  15. }
  16. class fileStorager
  17. {
  18.         use fileLogger,sysLogger
  19.         {
  20.                 fileLogger::logmessage insteadof sysLogger;           //insteadof使用sysLogger操作
  21.                 sysLogger::logmessage as private logsysmessage;       //as关键字重命名该Trait,后边的private修改了操作的可见性
  22.         }
  23.         
  24.         function store($data)
  25.         {
  26.                 //..
  27.                 $this->logmessage($message);
  28.                 $this->logsysmessage($message);
  29.         }
  30. }
  31. ?>
复制代码

我们在use子句中使用了两个不同的logging(日志记录)Trait.由于每个Trait都实现了相同的logmessage()方法,我们必须指定具体使用那个.如果不指定,PHP将产生致命错误,因为PHP无法解决此种冲突
使用insteadof关键字,可以指定要使用的Trait,如下代码所示:
fileLogger::logmessage insteadof sysLongger;
以上代码显式地告诉PHP使用fileLogger Trait的logmessage()方法.但是,在这个示例中,我们也需要访问sysLogger Trait的logmessage()方法.要解决此问题,可以通过as关键字重命名该Trait,如下代码所示:
sysLogger::logmessage as private logsysmessage;
sysLogger的logsysmessage()方法就可以用了,请注意,在这个示例中,其实是修改了方法的可见范围.这并不是必须的,介绍它的原因是说明这是可行的
还可以进一步构建完全由其他Trait组成或包含的Trait.这也就是真正实现水平组合特性.要实现水平组合,可以在Trait内使用use语句,就像在类中使用

page类提供了简单灵活的方法来创建TAL页面
  1. <?php
  2. class Page                                       //声明类
  3. {
  4.         //class Page's attributes
  5.         public $content;                            //属性
  6.         public $title="TLA Consulting Pty Ltd";     //属性
  7.         public $keywords="TLA Consulting,Three Letter Abbreviation,    //属性
  8.                          some of my best friends are search engines";
  9.         public $buttons=array("Home"=>"home.php",           //属性
  10.                          "Contact"=>"contact.php",                     
  11.                          "Services"=>"services.php",
  12.                                                  "site Map"=>"map.php"                                                
  13.                                                  );
  14.     //class Page's operations
  15.     public         function _set($name,$value)               //_set()给私有属性赋值,_get()获取私有属性值
  16.         {
  17.                 $this->$name=$value;
  18.         }
  19.         public function Display()                  //创建Display操作,显示网页格式
  20.         {
  21.                 echo "<html>\n<head>\n";               //输出头部head   
  22.                 $this->DisplayTitle();
  23.                 $this->DisplayKeyworde();
  24.                 $this->DisplayStyles();               
  25.                 echo"</head>\n<body>\n";               //输出主体body
  26.                 $this->DisplayHeader();
  27.                 $this->DisplayMenu($this->buttons);     
  28.                 echo $this->content;                    //引用content属性
  29.                 $this->DisplayFooter();                 //引用页脚
  30.                 echo "</body>\n</html>\n";
  31.         }
  32.         public function DisplayTitle()                 //创建DisplayTitle操作
  33.         {
  34.                 echo "<title>".$this->title."</title>";    //输出<title>
  35.         }
  36.         public function DisplayKeyworde()              //创建DisplayKeyworde操作
  37.         {
  38.                 echo "<meat name='keywords' content='".$this->keywords."'/>";     输出<meat>
  39.         }
  40.         public function DisplayStyles()                //创建DisplayStyles操作
  41.         {
  42.                 ?>
  43.                 <link href="styles.css" type="text/css" rel="stylesheet">
  44.                 <?php                                      //PHP方式输出<link>
  45.         }
  46.         public function DisplayHeader()            //创建DisplayHeader操作   
  47.         {
  48.                 ?>
  49.                 <!-- page header -->
  50.                 <header>
  51.                   <img src="logo.gif" alt="TLA logo" height="70" width="70" />
  52.                   <h1>TLA Consulting</h1>
  53.                 </header>
  54.         <?php                                                  //输出<header>
  55.         }
  56.         public function DisplayMenu($buttons)             //创建DisplayMenu操作  
  57.         {
  58.                 echo "<!-- menu -->
  59.                 <nav>";
  60.                 while (list($name,$url)=each($buttons)){      //each($buttons)获取返回数组的键名和键值,list($name,$url)把数组中的值赋值给变量$name和$url
  61.                         $this->DisplayButton($name,$url,
  62.                      !$this->IsURLCurrentPage($url));
  63.                         }
  64.                         echo "</nav>\n";                  
  65.         }                                                   //输出<nav>
  66.         public function IsURLCurrentPage($url)              //创建IsURLCurrentPage操作
  67.         {
  68.                 if(strpos($_SERVER['PHP_SELF'],$url)===false)   //$_SERVER['PHP_SELF']获取当前页面地址,strpos($_SERVER['PHP_SELF'],$url)在当前页面地址中查找$url
  69.                 {
  70.                         return false;                               //如果成功在当前页面获取到的地址中有字符串$url,返回flesh
  71.                 }
  72.                 else
  73.                 {
  74.                         return true;                                //否则返回true
  75.                 }
  76.         }                                      
  77.         public function DisplayButton($name,$url,$active=true)
  78.         {
  79.                 if($active){?>
  80.                 <div class="menuitem">
  81.                  <a href="<?=$url?>">
  82.                   <img src="s-logo.gif" alt="" height="20" windth="20" />
  83.                   <span class="menutext"><?=$name?></span>
  84.                   </a>
  85.                   </div>
  86.                   <?php                                       //如果返回true执行这里
  87.                 }else{ ?>
  88.                         <div class="menuitem">
  89.                         <img src="side-logo.gif">
  90.                         <span class="menutext"><?=$name?></span>
  91.                         </div>
  92.                         <?php                                     //否则执行这里
  93.                 }
  94.         }
  95.         public function DisplayFooter()                //创建DisplayFooter
  96.         {
  97.                 ?>
  98.                 <!-- page footer-->
  99.                 <footer>
  100.                   <p>&copy;TLA Consulting Pty Ltd.<br />
  101.           Please see our
  102.           <a href="legal.php">legal information page</a>.</p>
  103.         </footer>
  104.         <?php               
  105.            }
  106. }
  107. ?>
复制代码


首页使用page类完成生成页面的大部分工作
  1. <?php
  2. require("page.php");              //引入page.php
  3. $homepage= new Page();            //创建$homepage对象
  4. //$homepage对象访问content属性
  5. $homepage->content="<!-- page content -->              
  6.                     <section>
  7.                                         <h2>Welcome to the home of TLA Consulting.</h2>
  8.                                         <p>Please take some time to get to konw us.</p>
  9.                                         <p>We specialize in serving your business needs
  10.                                         and hope to hear from you soon.</p>
  11.                                         </section>";
  12. $homepage->Display();           //引用Display操作                                                                                
  13. ?>
复制代码


使用类级别常量
PHP提供了类级别常量思想.这个常量可以在不需要初始化该类的情况下使用,如下代码所示:
<?php
class Math
{
  const pi=3.1415926;
}
echo "Math::pi=".Math::pi;      
?>
输出结果:
Math::pi=3.1415926
可以通过::操作符并指定常量所属的类来访问类级别常量,如上所示

static静态化引用
<?PHP
class Math
{
  static function squared($input)              //创建静态操作
   {
     return $input*$input;
   }
}
echo Math::squared(8);                      //静态引用不能使用this关键字
?>
输出结果:
64

instanceof关键字允许检查一个对象的类型,它可以检查一个对象是否是特定类的实例.是否是从某个类继承过来或者是否实现了某个接口.instanceof关键字是一个高效率的条件操作符,如前面的示例中,类B作为类A的子类,如下语句:
  {$b instanceof B}                将返回true
  {$b instanceof A}                将返回true
  {$b instanceof Display}        将返回true
以上这些语句都是假设类A,类B接口Display都位于当前的作用域;否则将产生一个错误
function check_hint(B $someclass)         //要求$someclass必须是类B的实例
{
    //....
}
如果传入了类A的一个实例会出现致命错误
如果指定的是类A而传入类B的实例将不会产生错误,因为类B继承了类A
在相同函数有多个实现的继承曾级中,可以使用延迟静态绑定来确定调用具体类的方法.如下:
<?PHP
class A{
  public static function whichclass(){
     echo _CLASS_;
}
  public static function test(){
    self::whichclass();
}
}
class B extends A{
  public static function whichclass(){
    echo _CLASS_;
}
}
A::test();
B::test();
?>
都是输出的类A当前的类类名
self关键字和static都是获取当前类名,不同点如下:
*  1.在一个类A中,self::who() 等同于 static::who()
*  2.当子类B继承父类A,子类B::test(),调用的时候,区别:
*      test()方法调用 self::who() 调用父类的who()方法
*      test()方法调用 static::who()调用的是子类的who()方法

clone关键字,允许赋值一个已有对象
$c=clone $b;
将创建对象$b的副本,具有与$b相同的类型与属性值

_call()实现方法重载
call()方法必须带有两个参数,第一个包含了被调用的方法名称,而第二个参数包含了传递给该方法的参数数组
public function _call($method,$p)              //方法重载
{
  if ($method =="display"){                     
    if(is_object($p[0])){
      $this->displayobject($p[0]);
    }else if(is_array($p[0])){
       $this->displayArray($p[0]);
      }else{
        $this->displayScalar($p[0]);   
        }
   }
}
$ov=new overload;
$ov->display(array(1,2,3));
$ov->display('cat');

另一个特殊的函数时_autoload().它不是一个类方法,而是一个单独的函数,也就是说,可以在任何类声明之外声明这个函数.如果实现了这个函数,它将在实例化一个还没有被声明的类时自动调用
_autoload()方法的主要用途是尝试引入特定文件,而又需要该文件来初始化所需类
function _autoload($name)
{
  include_once $name.".php";
}
该实例将引入一个具有与该类相同名称的文件

foreach()循环遍历一个对象的所以属性,就像数组方式一样
foreach 仅能用于数组,当试图将其用于其它数据类型或者一个未初始化的变量时会产生错误。有两种语法,第二种是第一种的有用的扩展。
foreach(array_expression as $value) statement
foreach(array_expression as $key => $value) statement
    第一种格式遍历给定的 array_expression 数组。每次循环中,当前单元的值被赋给 $value 并且数组内部的指针向前移一步(因此下一次循环中将会得到下一个单元)。

    第二种格式做同样的事,只是除了当前单元的值以外,键值也会在每次循环中被赋给变量 $key。

如果需要更复杂的行为,可以实现一个迭代器(iterator).要实现一个迭代器,被迭代的类必须实现IteratorAggregate接口,并且定义一个能够返回该迭代类实例的getIterator方法,迭代器和基类示例程序清单如下所示:
  1. <?PHP
  2. class ObjectIterator implements Iterator{             //implements实现接口,Iterator迭代器;ObjectIterator实现了接口Iterator                        
  3.         private $obj;                                     //对象
  4.         private $count;                                   //数据元素的数量
  5.         private $currentIndex;                            //当前指针

  6. function __construct($obj)                           //构造函数
  7. {
  8.         $this->obj=$obj;
  9.         $this->count=count($this->obj->data);
  10. }
  11. function rewind()                                   //重置迭代器,指针指向0
  12. {
  13.         $this->currentIndex=0;                          
  14. }
  15. function valid()                                   //验证迭代器是否有数据
  16. {
  17.         return $this->currentIndex<$this->count;
  18. }
  19. function key()                                    //迭代器key当前位置
  20. {
  21.         return $this->currentIndex;
  22. }
  23. function current()                                //获取当前内容
  24. {
  25.         return $this->obj->data[$this->currentIndex];
  26. }
  27. function next()                                   //移动key到下一个
  28. {
  29.         $this->currentIndex++;
  30. }
  31. }

  32. class bject implements IteratorAggregate    //object实现了接口IteratorAggregate
  33. {
  34.         public $data=array();                    //属性
  35.        
  36.         function __construct($in)                 //构造函数
  37.         {
  38.                 $this->data=$in;
  39.         }
  40.         function getIterator()                   //getIterator方法
  41.         {
  42.                 return new ObjectIterator($this);    //创建ObjectIterator对象,并返回实例名
  43.         }
  44. }
  45. $myObject =new bject(array(2,4,6,8,10));             //创建对象       
  46. $myIterator=$myObject->getIterator();
  47. for($myIterator->rewind();$myIterator->valid();$myIterator->next())
  48. {
  49.         $key=$myIterator->key();
  50.         $value=$myIterator->current();
  51.         echo $key."=>".$value."<br />";
  52. }
  53. ?>
复制代码

输出结果:
0=>2
1=>4
2=>6
3=>8
4=>10

在很多方面,生成器与迭代器类似,但生成器更简单.可以理解生成器为:定义时像函数,运行时像迭代器
编写生成器与普通函数的区别在于:生成器需要使用yield关键字返回结果.而普通函数使用return关键字返回结果,
必须在foreach循环中调用生成器函数,这将创建一个能够保存生成器函数内部状态的Generator对象.在外部foreach循环的每次迭代中,生成器执行下一个内部迭代
使用生成器打印fizzbuzz序列
  1. <?PHP
  2. function fizzbuzz($start,$end)
  3. {
  4.         $current=$start;                       //$current=1,$end=20
  5.         while($current<=$end){
  6.                 if($current%3==0&&$current%5==0){
  7.                         yield"fuzzbuzz";
  8.         }else if($current%3==0){
  9.                 yield"fizz";
  10.         }else if($current%5==0){
  11.                 yield"buzz";
  12.         }else{
  13.                 yield $current;
  14.         }
  15.         $current++;                             //每循环一次$current+1,当$current=21时停止循环
  16.         }
  17. }
  18. foreach(fizzbuzz(1,20) as $number){         
  19.         echo $number.'<br />';                  //循环取出数组元素1-20的值并输出
  20. }
  21. ?>
复制代码

输出结果:
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fuzzbuzz
16
17
fizz
19
buzz

__toString()  是魔术方法的一种,具体用途是当一个对象被当作字符串对待的时候,会触发这个魔术方法 以下说明摘自PHP官方手册

public string __toString ( void )
__toString() 方法用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。此方法必须返回一个字符串,否则将发出一条 E_RECOVERABLE_ERROR 级别的致命错误。

Warning
不能在 __toString() 方法中抛出异常。这么做会导致致命错误。
  1. <?php
  2. // Declare a simple class
  3. class TestClass
  4. {
  5.     public $foo;

  6.     public function __construct($foo)
  7.     {
  8.         $this->foo = $foo;
  9.     }

  10.     public function __toString() {
  11.         return $this->foo;
  12.     }
  13. }

  14. $class = new TestClass('Hello');         //实例化类
  15. echo $class;
  16. ?>
复制代码

输出结果:
Hello

php的面向对象特性还包括反射api.反射是通过访问已有类和对象来找到类和对象结构及内容的能力
显示page类的信息
  1. <?php
  2. require_once("page.PHP");
  3. $class=new ReflectionClass("page");
  4. echo "<pre>".$class."</pre>";
  5. ?>
复制代码

输出结果:
Class [  class Page ] {
  @@ G:\phpstudy\WWW\page.php 2-106

  - Constants [0] {
  }

  - Static properties [0] {
  }

  - Static methods [0] {
  }

  - Properties [4] {
    Property [  public $content ]
    Property [  public $title ]
    Property [  public $keywords ]
    Property [  public $buttons ]
  }

  - Methods [10] {
    Method [  public method _set ] {
      @@ G:\phpstudy\WWW\page.php 15 - 18

      - Parameters [2] {
        Parameter #0 [  $name ]
        Parameter #1 [  $value ]
      }
    }

    Method [  public method Display ] {
      @@ G:\phpstudy\WWW\page.php 19 - 31
    }

    Method [  public method DisplayTitle ] {
      @@ G:\phpstudy\WWW\page.php 32 - 35
    }

    Method [  public method DisplayKeyworde ] {
      @@ G:\phpstudy\WWW\page.php 36 - 39
    }

    Method [  public method DisplayStyles ] {
      @@ G:\phpstudy\WWW\page.php 40 - 45
    }

    Method [  public method DisplayHeader ] {
      @@ G:\phpstudy\WWW\page.php 46 - 55
    }

    Method [  public method DisplayMenu ] {
      @@ G:\phpstudy\WWW\page.php 56 - 65

      - Parameters [1] {
        Parameter #0 [  $buttons ]
      }
    }

    Method [  public method IsURLCurrentPage ] {
      @@ G:\phpstudy\WWW\page.php 66 - 76

      - Parameters [1] {
        Parameter #0 [  $url ]
      }
    }

    Method [  public method DisplayButton ] {
      @@ G:\phpstudy\WWW\page.php 77 - 94

      - Parameters [3] {
        Parameter #0 [  $name ]
        Parameter #1 [  $url ]
        Parameter #2 [  $active = true ]
      }
    }

    Method [  public method DisplayFooter ] {
      @@ G:\phpstudy\WWW\page.php 95 - 105
    }
  }
}

PHP 命名空间(namespace)
PHP 命名空间(namespace)是在PHP 5.3中加入的,如果你学过C#和Java,那命名空间就不算什么新事物。 不过在PHP当中还是有着相当重要的意义。

PHP 命名空间可以解决以下两类问题:

用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。
为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。
定义命名空间
默认情况下,所有常量、类和函数名都放在全局空间下,就和PHP支持命名空间之前一样。

命名空间通过关键字namespace 来声明。如果一个文件中包含命名空间,它必须在其它所有代码之前声明命名空间。语法格式如下;

  1. <?php  
  2. // 定义代码在 'MyProject' 命名空间中  
  3. namespace MyProject;  

  4. // ... 代码 ...
复制代码

你也可以在同一个文件中定义不同的命名空间代码,如:

  1. <?php  
  2. namespace MyProject;

  3. const CONNECT_OK = 1;
  4. class Connection { /* ... */ }
  5. function connect() { /* ... */  }

  6. namespace AnotherProject;

  7. const CONNECT_OK = 1;
  8. class Connection { /* ... */ }
  9. function connect() { /* ... */  }
  10. ?>
复制代码

不建议使用这种语法在单个文件中定义多个命名空间。建议使用下面的大括号形式的语法。

  1. <?php
  2. namespace MyProject {
  3.     const CONNECT_OK = 1;
  4.     class Connection { /* ... */ }
  5.     function connect() { /* ... */  }
  6. }

  7. namespace AnotherProject {
  8.     const CONNECT_OK = 1;
  9.     class Connection { /* ... */ }
  10.     function connect() { /* ... */  }
  11. }
  12. ?>
复制代码

将全局的非命名空间中的代码与命名空间中的代码组合在一起,只能使用大括号形式的语法。全局代码必须用一个不带名称的 namespace 语句加上大括号括起来,例如:

  1. <?php
  2. namespace MyProject {

  3. const CONNECT_OK = 1;
  4. class Connection { /* ... */ }
  5. function connect() { /* ... */  }
  6. }

  7. namespace { // 全局代码
  8. session_start();
  9. $a = MyProject\connect();
  10. echo MyProject\Connection::start();
  11. }
  12. ?>
复制代码

在声明命名空间之前唯一合法的代码是用于定义源文件编码方式的 declare 语句。所有非 PHP 代码包括空白符都不能出现在命名空间的声明之前。

  1. <?php
  2. declare(encoding='UTF-8'); //定义多个命名空间和不包含在命名空间中的代码
  3. namespace MyProject {

  4. const CONNECT_OK = 1;
  5. class Connection { /* ... */ }
  6. function connect() { /* ... */  }
  7. }

  8. namespace { // 全局代码
  9. session_start();
  10. $a = MyProject\connect();
  11. echo MyProject\Connection::start();
  12. }
  13. ?>
复制代码

以下代码会出现语法错误:

<html>
  1. <?php
  2. namespace MyProject; // 命名空间前出现了“<html>” 会致命错误 - 命名空间必须是程序脚本的第一条语句
  3. ?>
复制代码

子命名空间
与目录和文件的关系很像,PHP 命名空间也允许指定层次化的命名空间的名称。因此,命名空间的名字可以使用分层次的方式定义:

  1. <?php
  2. namespace MyProject\Sub\Level;  //声明分层次的单个命名空间

  3. const CONNECT_OK = 1;
  4. class Connection { /* ... */ }
  5. function Connect() { /* ... */  }

  6. ?>
复制代码

上面的例子创建了常量 MyProject\Sub\Level\CONNECT_OK,类 MyProject\Sub\Level\Connection 和函数 MyProject\Sub\Level\Connect。

命名空间使用
PHP 命名空间中的类名可以通过三种方式引用:

非限定名称,或不包含前缀的类名称,例如 $a=new foo(); 或 foo::staticmethod();。如果当前命名空间是 currentnamespace,foo 将被解析为 currentnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,则 foo 会被解析为foo。 警告:如果命名空间中的函数或常量未定义,则该非限定的函数名称或常量名称会被解析为全局函数名称或常量名称。

限定名称,或包含前缀的名称,例如 $a = new subnamespace\foo(); 或 subnamespace\foo::staticmethod();。如果当前的命名空间是 currentnamespace,则 foo 会被解析为 currentnamespace\subnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,foo 会被解析为subnamespace\foo。

完全限定名称,或包含了全局前缀操作符的名称,例如, $a = new \currentnamespace\foo(); 或 \currentnamespace\foo::staticmethod();。在这种情况下,foo 总是被解析为代码中的文字名(literal name)currentnamespace\foo。

下面是一个使用这三种方式的实例:

file1.php 文件代码

  1. <?php
  2. namespace Foo\Bar\subnamespace;

  3. const FOO = 1;
  4. function foo() {}
  5. class foo
  6. {
  7.     static function staticmethod() {}
  8. }
  9. ?>
复制代码

file2.php 文件代码

  1. <?php
  2. namespace Foo\Bar;
  3. include 'file1.php';

  4. const FOO = 2;
  5. function foo() {}
  6. class foo
  7. {
  8.     static function staticmethod() {}
  9. }

  10. /* 非限定名称 */
  11. foo(); // 解析为函数 Foo\Bar\foo
  12. foo::staticmethod(); // 解析为类 Foo\Bar\foo ,方法为 staticmethod
  13. echo FOO; // 解析为常量 Foo\Bar\FOO

  14. /* 限定名称 */
  15. subnamespace\foo(); // 解析为函数 Foo\Bar\subnamespace\foo
  16. subnamespace\foo::staticmethod(); // 解析为类 Foo\Bar\subnamespace\foo,
  17.                                   // 以及类的方法 staticmethod
  18. echo subnamespace\FOO; // 解析为常量 Foo\Bar\subnamespace\FOO
  19.                                  
  20. /* 完全限定名称 */
  21. \Foo\Bar\foo(); // 解析为函数 Foo\Bar\foo
  22. \Foo\Bar\foo::staticmethod(); // 解析为类 Foo\Bar\foo, 以及类的方法 staticmethod
  23. echo \Foo\Bar\FOO; // 解析为常量 Foo\Bar\FOO
  24. ?>
复制代码

注意访问任意全局类、函数或常量,都可以使用完全限定名称,例如 \strlen() 或 \Exception 或 \INI_ALL。

在命名空间内部访问全局类、函数和常量:

  1. <?php
  2. namespace Foo;

  3. function strlen() {}
  4. const INI_ALL = 3;
  5. class Exception {}

  6. $a = \strlen('hi'); // 调用全局函数strlen
  7. $b = \INI_ALL; // 访问全局常量 INI_ALL
  8. $c = new \Exception('error'); // 实例化全局类 Exception
  9. ?>
复制代码

命名空间和动态语言特征
PHP 命名空间的实现受到其语言自身的动态特征的影响。因此,如果要将下面的代码转换到命名空间中,动态访问元素。

example1.php 文件代码:

  1. <?php
  2. class classname
  3. {
  4.     function __construct()
  5.     {
  6.         echo __METHOD__,"\n";
  7.     }
  8. }
  9. function funcname()
  10. {
  11.     echo __FUNCTION__,"\n";
  12. }
  13. const constname = "global";

  14. $a = 'classname';
  15. $obj = new $a; // prints classname::__construct
  16. $b = 'funcname';
  17. $b(); // prints funcname
  18. echo constant('constname'), "\n"; // prints global
  19. ?>
复制代码

必须使用完全限定名称(包括命名空间前缀的类名称)。注意因为在动态的类名称、函数名称或常量名称中,限定名称和完全限定名称没有区别,因此其前导的反斜杠是不必要的。

动态访问命名空间的元素

  1. <?php
  2. namespace namespacename;
  3. class classname
  4. {
  5.     function __construct()
  6.     {
  7.         echo __METHOD__,"\n";
  8.     }
  9. }
  10. function funcname()
  11. {
  12.     echo __FUNCTION__,"\n";
  13. }
  14. const constname = "namespaced";

  15. include 'example1.php';

  16. $a = 'classname';
  17. $obj = new $a; // 输出 classname::__construct
  18. $b = 'funcname';
  19. $b(); // 输出函数名
  20. echo constant('constname'), "\n"; // 输出 global

  21. /* 如果使用双引号,使用方法为 "\\namespacename\\classname"*/
  22. $a = '\namespacename\classname';
  23. $obj = new $a; // 输出 namespacename\classname::__construct
  24. $a = 'namespacename\classname';
  25. $obj = new $a; // 输出 namespacename\classname::__construct
  26. $b = 'namespacename\funcname';
  27. $b(); // 输出 namespacename\funcname
  28. $b = '\namespacename\funcname';
  29. $b(); // 输出 namespacename\funcname
  30. echo constant('\namespacename\constname'), "\n"; // 输出 namespaced
  31. echo constant('namespacename\constname'), "\n"; // 输出 namespaced
  32. ?>
复制代码

namespace关键字和__NAMESPACE__常量
PHP支持两种抽象的访问当前命名空间内部元素的方法,__NAMESPACE__ 魔术常量和namespace关键字。

常量__NAMESPACE__的值是包含当前命名空间名称的字符串。在全局的,不包括在任何命名空间中的代码,它包含一个空的字符串。

__NAMESPACE__ 示例, 在命名空间中的代码

  1. <?php
  2. namespace MyProject;

  3. echo '"', __NAMESPACE__, '"'; // 输出 "MyProject"
  4. ?>
  5. __NAMESPACE__ 示例,全局代码

  6. <?php

  7. echo '"', __NAMESPACE__, '"'; // 输出 ""
  8. ?>
复制代码

常量 __NAMESPACE__ 在动态创建名称时很有用,例如:

使用__NAMESPACE__动态创建名称

  1. <?php
  2. namespace MyProject;

  3. function get($classname)
  4. {
  5.     $a = __NAMESPACE__ . '\\' . $classname;
  6.     return new $a;
  7. }
  8. ?>
复制代码

关键字 namespace 可用来显式访问当前命名空间或子命名空间中的元素。它等价于类中的 self 操作符。

namespace操作符,命名空间中的代码

  1. <?php
  2. namespace MyProject;

  3. use blah\blah as mine; // see "Using namespaces: importing/aliasing"

  4. blah\mine(); // calls function blah\blah\mine()
  5. namespace\blah\mine(); // calls function MyProject\blah\mine()

  6. namespace\func(); // calls function MyProject\func()
  7. namespace\sub\func(); // calls function MyProject\sub\func()
  8. namespace\cname::method(); // calls static method "method" of class MyProject\cname
  9. $a = new namespace\sub\cname(); // instantiates object of class MyProject\sub\cname
  10. $b = namespace\CONSTANT; // assigns value of constant MyProject\CONSTANT to $b
  11. ?>
复制代码

namespace操作符, 全局代码

  1. <?php

  2. namespace\func(); // calls function func()
  3. namespace\sub\func(); // calls function sub\func()
  4. namespace\cname::method(); // calls static method "method" of class cname
  5. $a = new namespace\sub\cname(); // instantiates object of class sub\cname
  6. $b = namespace\CONSTANT; // assigns value of constant CONSTANT to $b
  7. ?>
复制代码

使用命名空间:别名/导入
PHP 命名空间支持 有两种使用别名或导入方式:为类名称使用别名,或为命名空间名称使用别名。

在PHP中,别名是通过操作符 use 来实现的. 下面是一个使用所有可能的三种导入方式的例子:

1、使用use操作符导入/使用别名

  1. <?php
  2. namespace foo;
  3. use My\Full\Classname as Another;

  4. // 下面的例子与 use My\Full\NSname as NSname 相同
  5. use My\Full\NSname;

  6. // 导入一个全局类
  7. use \ArrayObject;

  8. $obj = new namespace\Another; // 实例化 foo\Another 对象
  9. $obj = new Another; // 实例化 My\Full\Classname 对象
  10. NSname\subns\func(); // 调用函数 My\Full\NSname\subns\func
  11. $a = new ArrayObject(array(1)); // 实例化 ArrayObject 对象
  12. // 如果不使用 "use \ArrayObject" ,则实例化一个 foo\ArrayObject 对象
  13. ?>
复制代码

2、 一行中包含多个use语句

  1. <?php
  2. use My\Full\Classname as Another, My\Full\NSname;

  3. $obj = new Another; // 实例化 My\Full\Classname 对象
  4. NSname\subns\func(); // 调用函数 My\Full\NSname\subns\func
  5. ?>
复制代码

导入操作是在编译执行的,但动态的类名称、函数名称或常量名称则不是。

3、导入和动态名称

  1. <?php
  2. use My\Full\Classname as Another, My\Full\NSname;

  3. $obj = new Another; // 实例化一个 My\Full\Classname 对象
  4. $a = 'Another';
  5. $obj = new $a;      // 实际化一个 Another 对象
  6. ?>
复制代码

另外,导入操作只影响非限定名称和限定名称。完全限定名称由于是确定的,故不受导入的影响。

4、导入和完全限定名称

  1. <?php
  2. use My\Full\Classname as Another, My\Full\NSname;

  3. $obj = new Another; // 实例化 My\Full\Classname 类
  4. $obj = new \Another; // 实例化 Another 类
  5. $obj = new Another\thing; // 实例化 My\Full\Classname\thing 类
  6. $obj = new \Another\thing; // 实例化 Another\thing 类
  7. ?>
复制代码

使用命名空间:后备全局函数/常量
在一个命名空间中,当 PHP 遇到一个非限定的类、函数或常量名称时,它使用不同的优先策略来解析该名称。类名称总是解析到当前命名空间中的名称。因此在访问系统内部或不包含在命名空间中的类名称时,必须使用完全限定名称,例如:

1、在命名空间中访问全局类

  1. <?php
  2. namespace A\B\C;
  3. class Exception extends \Exception {}

  4. $a = new Exception('hi'); // $a 是类 A\B\C\Exception 的一个对象
  5. $b = new \Exception('hi'); // $b 是类 Exception 的一个对象

  6. $c = new ArrayObject; // 致命错误, 找不到 A\B\C\ArrayObject 类
  7. ?>
复制代码

对于函数和常量来说,如果当前命名空间中不存在该函数或常量,PHP 会退而使用全局空间中的函数或常量。

2、 命名空间中后备的全局函数/常量

  1. <?php
  2. namespace A\B\C;

  3. const E_ERROR = 45;
  4. function strlen($str)
  5. {
  6.     return \strlen($str) - 1;
  7. }

  8. echo E_ERROR, "\n"; // 输出 "45"
  9. echo INI_ALL, "\n"; // 输出 "7" - 使用全局常量 INI_ALL

  10. echo strlen('hi'), "\n"; // 输出 "1"
  11. if (is_array('hi')) { // 输出 "is not array"
  12.     echo "is array\n";
  13. } else {
  14.     echo "is not array\n";
  15. }
  16. ?>
复制代码

全局空间
如果没有定义任何命名空间,所有的类与函数的定义都是在全局空间,与 PHP 引入命名空间概念前一样。在名称前加上前缀 \ 表示该名称是全局空间中的名称,即使该名称位于其它的命名空间中时也是如此。

使用全局空间说明

  1. <?php
  2. namespace A\B\C;

  3. /* 这个函数是 A\B\C\fopen */
  4. function fopen() {
  5.      /* ... */
  6.      $f = \fopen(...); // 调用全局的fopen函数
  7.      return $f;
  8. }
  9. ?>
复制代码

命名空间的顺序
自从有了命名空间之后,最容易出错的该是使用类的时候,这个类的寻找路径是什么样的了。

  1. <?php
  2. namespace A;
  3. use B\D, C\E as F;

  4. // 函数调用

  5. foo();      // 首先尝试调用定义在命名空间"A"中的函数foo()
  6.             // 再尝试调用全局函数 "foo"

  7. \foo();     // 调用全局空间函数 "foo"

  8. my\foo();   // 调用定义在命名空间"A\my"中函数 "foo"

  9. F();        // 首先尝试调用定义在命名空间"A"中的函数 "F"
  10.             // 再尝试调用全局函数 "F"

  11. // 类引用

  12. new B();    // 创建命名空间 "A" 中定义的类 "B" 的一个对象
  13.             // 如果未找到,则尝试自动装载类 "A\B"

  14. new D();    // 使用导入规则,创建命名空间 "B" 中定义的类 "D" 的一个对象
  15.             // 如果未找到,则尝试自动装载类 "B\D"

  16. new F();    // 使用导入规则,创建命名空间 "C" 中定义的类 "E" 的一个对象
  17.             // 如果未找到,则尝试自动装载类 "C\E"

  18. new \B();   // 创建定义在全局空间中的类 "B" 的一个对象
  19.             // 如果未发现,则尝试自动装载类 "B"

  20. new \D();   // 创建定义在全局空间中的类 "D" 的一个对象
  21.             // 如果未发现,则尝试自动装载类 "D"

  22. new \F();   // 创建定义在全局空间中的类 "F" 的一个对象
  23.             // 如果未发现,则尝试自动装载类 "F"

  24. // 调用另一个命名空间中的静态方法或命名空间函数

  25. B\foo();    // 调用命名空间 "A\B" 中函数 "foo"

  26. B::foo();   // 调用命名空间 "A" 中定义的类 "B" 的 "foo" 方法
  27.             // 如果未找到类 "A\B" ,则尝试自动装载类 "A\B"

  28. D::foo();   // 使用导入规则,调用命名空间 "B" 中定义的类 "D" 的 "foo" 方法
  29.             // 如果类 "B\D" 未找到,则尝试自动装载类 "B\D"

  30. \B\foo();   // 调用命名空间 "B" 中的函数 "foo"

  31. \B::foo();  // 调用全局空间中的类 "B" 的 "foo" 方法
  32.             // 如果类 "B" 未找到,则尝试自动装载类 "B"

  33. // 当前命名空间中的静态方法或函数

  34. A\B::foo();   // 调用命名空间 "A\A" 中定义的类 "B" 的 "foo" 方法
  35.               // 如果类 "A\A\B" 未找到,则尝试自动装载类 "A\A\B"

  36. \A\B::foo();  // 调用命名空间 "A" 中定义的类 "B" 的 "foo" 方法
  37.               // 如果类 "A\B" 未找到,则尝试自动装载类 "A\B"
  38. ?>
复制代码

名称解析遵循下列规则:

对完全限定名称的函数,类和常量的调用在编译时解析。例如 new \A\B 解析为类 A\B。
所有的非限定名称和限定名称(非完全限定名称)根据当前的导入规则在编译时进行转换。例如,如果命名空间 A\B\C 被导入为 C,那么对 C\D\e() 的调用就会被转换为 A\B\C\D\e()。
在命名空间内部,所有的没有根据导入规则转换的限定名称均会在其前面加上当前的命名空间名称。例如,在命名空间 A\B 内部调用 C\D\e(),则 C\D\e() 会被转换为 A\B\C\D\e() 。
非限定类名根据当前的导入规则在编译时转换(用全名代替短的导入名称)。例如,如果命名空间 A\B\C 导入为C,则 new C() 被转换为 new A\B\C() 。
在命名空间内部(例如A\B),对非限定名称的函数调用是在运行时解析的。例如对函数 foo() 的调用是这样解析的:
在当前命名空间中查找名为 A\B\foo() 的函数
尝试查找并调用 全局(global) 空间中的函数 foo()。
在命名空间(例如A\B)内部对非限定名称或限定名称类(非完全限定名称)的调用是在运行时解析的。下面是调用 new C() 及 new D\E() 的解析过程: new C()的解析:
在当前命名空间中查找A\B\C类。
尝试自动装载类A\B\C。
new D\E()的解析:
在类名称前面加上当前命名空间名称变成:A\B\D\E,然后查找该类。
尝试自动装载类 A\B\D\E。
为了引用全局命名空间中的全局类,必须使用完全限定名称 new \C()。

我已经实在不想看这一章了,对新手来说这一章说的都看不懂,书上可以说啥都没说

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

快速回复 返回顶部 返回列表