PHP 7.4 中增加了类型化类属性,对 php 的类型系统进行了重大改进。这些更改完全是自愿加入的,不会破坏以前的版本。
在本文中,我们将深入了解该功能,但首先让我们总结一下最重要的几点:
这些更改自 PHP 7.4 起可用,计划于 2019 年 11 月发布它们仅在类中可用,并且需要访问修饰符:public、protected 或 private;或 var允许所有类型,但 void 和 callable 除外他们的实际情况是这样的:
classFoo{public int $a;public?string $b='foo';private Foo $prop;protectedstatic string $static='default';}如果你不确定类型的额外好处,我建议您首先阅读这篇文章。
未初始化
在进入正题之前,首先要探讨一个与类型属性有关的重要方面。
不管你第一眼看到这段代码是怎么想的,但它的确是合法的
classFoo{public int $bar;}$foo=newFoo;即便是类的实例化后 $bar 值仍不是整数值的情况下,PHP 也只是会在访问 $bar 时才会报错:
var_dump($foo->bar);Fatal error: Uncaught Error: Typed property Foo::$barmust not be accessed before initialization从错误消息中可以看出,出现了一种新的变量状态:未初始化 (uninitialized)
$bar 属性无论是否声明了类型,值都可以为 null。因此,无法确定类型属性是否设置。这就是增加变量「未初始化」状态的原因。
未初始化有四个方面需要注意:
无法读取未初始化的属性,一旦这么做,将引发致命错误;由于在访问属性时会检查未初始化状态,所以即使是不可为空的对象也可以使用未初始化属性;在读取未初始化属性时候之前可以对其进行写入;unset 操作会让类型属性变成未初始化状态,而非类型属性只会变成值为 null;特别要注意在对象实例化之后设置未初始化的类型属性是合法的:
classFoo{public int $a;}$foo=newFoo;$foo->a=1;// 合法$foo->a=null;// 非法虽然只会在读取属性值时检查未初始化状态,但在写入属性时会进行类型验证。这意味着任何无效的属性值都不会被设置。
默认值和构造函数
让我们仔细看看如何初始化类型属性值。对于标量类型,可以直接提供一个默认值
classFoo{public int $bar=4;public?string $baz=null;// 错误写法 public string $baz = null;publicarray$list=[1,2,3];}类型属性不能显示设置为 null,除非是可空类型。这看上去显而易见的,但是一些旧行为却允许这种操作
functionpassNull(int $i=null){/* … */}passNull(null);幸运的是,类型属性不允许这种令人疑惑的行为。还要注意,属性类型的默认值不可能为对象或者类,你应当使用构造器来设置这些值。
最明显的用来设置默认值的地方就是构造函数
classFoo{private int $a;publicfunction__construct(int $a){$this->a=$a;}}但也要记住我之前提到的内容:在构造函数之外写入未初始化 (uninitialized) 的属性是有效的。只要没有读取属性值的操作,编译器就不会执行未初始化的相关检查。
类型
那么到底哪些类型可以指定,又如何指定呢?我已经提到了指定属性类型只能在类中进行 (当前如此),并且它们需要一个访问修饰符或是属性前面的 var 关键字。
对于可用类型,几乎所有类型都可以使用,除了 void 和 callable 类型.
因为 void 意味着没有值,所以它不能用于指定一个值的类型也就说得过去了。然而 callback 就有一点细微不同了。
可见,PHP 中的 "callback" 可以这样写
$callable=[$this,'method'];假设你有以下 (无效) 代码:
classFoo{publiccallable$callable;publicfunction__construct(callable$callable){/* … */}}classBar{public Foo $foo;publicfunction__construct(){$this->foo=newFoo([$this,'method'])}privatefunctionmethod(){/* … */}}$bar=newBar;($bar->foo->callable)();在此例中,$callback 引用了私有的 Bar::method,但是是在 Foo 的上下文中被调用的。基于这个问题,决定不添加 callback 类型的支持。
不过这并不是什么大问题,因为 Closure(闭包) 是一种有效类型,它会记住构建它的 $this 上下文。
顺带一说,以下是所有可用类型的列表:
boolintfloatstringarrayiterableobject? (nullable)self & parentClasses & interfaces强制和严格类型
PHP,是我们既喜欢又反感的动态语言,它会尽可能地强制或转换类型。假设你在一个期望接受 int 的地方传入字符串,PHP 会试着自动转换该字符串:
functioncoerce(int $i){/* … */}coerce('1');// 1同样的原则也适用于已指定类型的属性,下面的代码是有效的,且会将'1' 转换为 1.
classBar{public int $i;}$bar=newBar;$bar->i='1';// 1如果你并不喜欢这种 (自动转换) 行为,可以通过声明严格类型来禁用它:
declare(strict_types=1);$bar=newBar;$bar->i='1';// 1Fatal error: Uncaught TypeError:Typed property Bar::$i must be int, string used类型差异和继承
即使 PHP 7.4 引入了 改进的类型差异 , 但是类型的属性仍然是不变的。这意味着以下写法是无效的:
classA{}classBextendsA{}classFoo{publicA$prop;}classBarextendsFoo{publicB$prop;}Fatal error: Type of Bar::$prop must be A(as in classFoo)如果上面的示例看起来不够明显的话,你可以查看以下内容:
classFoo{public self $prop;}classBarextendsFoo{public self $prop;}在运行代码之前,PHP 将在背后用它所引用的具体实现类来替换 self。这意味着在此本例中将抛出相同的错误。解决此问题的唯一方法是执行以下操作:
classFoo{public Foo $prop;}classBarextendsFoo{public Foo $prop;}谈到继承,您可能会发现很难想出任何好的用例来重写继承属性的类型。
尽管我同意这种观点,但值得注意的是更改继承属性的类型是可能实现的,前提是访问修饰符也必须从 private 更改为 protected 或 public。
以下代码是有效的:
classFoo{private int $prop;}classBarextendsFoo{public string $prop;}但是,从可空的类型改为不可空或反向的类型是不允许的。
classFoo{public int $a;public?int $b;}classBarextendsFoo{public?int $a;public int $b;}Fatal error: Type of Bar::$a must be int (as in classFoo)还有更多!
正如开头所说,类型化属性是 PHP 的 主要 补充。关于它们更多的内容,我建议您通读 RFC 以了解所有细节。
如果您不熟悉 PHP 7.4,则可能需要阅读 完整列表 中所做的更改和添加的功能。老实说,这是很长一段时间以来最好的发行版之一,值得您花时间!
简介先看看下面这个过程:
我们从未手动开启过PHP的相关进程,它是随着Apache的启动而运行的;PHP通过mod_php5.so模块和Apache相连(具体说来是SAPI,即服务器应用程序编程接口);PHP总共有三个模块:内核、Zend引擎、以及扩展层;PHP内核用来处理请求、文件流、错误处理等相关操作;Zend引擎(ZE)用以将源文件转换成机器语言,然后在虚拟机上运行它;扩展层是一组函数、类库和流,PHP使用它们来执行一些特定的操作。比如,我们需要mysql扩展来连接MySQL数据库;当ZE执行程序时可能会需要连接若干扩展,这时ZE将控制权交给扩展,等处理完特定任务后再返还;最后,ZE将程序运行结果返回给PHP内核,它再将结果传送给SAPI层,最终输出到浏览器上。深入探讨 等等,没有这么简单。以上过程只是个简略版,让我们再深入挖掘一下,看看幕后还发生了些什么。
Apache启动后,PHP解释程序也随之启动;PHP的启动过程有两步;第一步是初始化一些环境变量,这将在整个SAPI生命周期中发生作用;第二步是生成只针对当前请求的一些变量设置。PHP启动第一步 不清楚什么第一第二步是什么?别担心,我们接下来详细讨论一下。让我们先看看第一步,也是最主要的一步。要记住的是,第一步的操作在任何请求到达之前就发生了。
启动Apache后,PHP解释程序也随之启动;PHP调用各个扩展的MINIT方法,从而使这些扩展切换到可用状态。看看php.ini文件里打开了哪些扩展吧;MINIT的意思是“模块初始化”。各个模块都定义了一组函数、类库等用以处理其他请求。 一个典型的MINIT方法如下:PHP_MINIT_FUNCTION(extension_name){/* Initialize functions, classes etc */}PHP启动第二步
当一个页面请求发生时,SAPI层将控制权交给PHP层。于是PHP设置了用于回复本次请求所需的环境变量。同时,它还建立一个变量表,用来存放执行过程中产生的变量名和值。PHP调用各个模块的RINIT方法,即“请求初始化”。一个经典的例子是Session模块的RINIT,如果在php.ini中启用了Session模块,那在调用该模块的RINIT时就会初始化$_SESSION变量,并将相关内容读入;RINIT方法可以看作是一个准备过程,在程序执行之间就会自动启动。 一个典型的RINIT方法如下:PHP_RINIT_FUNCTION(extension_name) {/* Initialize session variables, pre-populate variables, redefine global variables etc */}PHP关闭第一步 如同PHP启动一样,PHP的关闭也分两步:
一旦页面执行完毕(无论是执行到了文件末尾还是用exit或die函数中止),PHP就会启动清理程序。它会按顺序调用各个模块的RSHUTDOWN方法。RSHUTDOWN用以清除程序运行时产生的符号表,也就是对每个变量调用unset函数。 一个典型的RSHUTDOWN方法如下:PHP_RSHUTDOWN_FUNCTION(extension_name) {/* Do memory management, unset all variables used in the last PHP call etc */}PHP关闭第二步 最后,所有的请求都已处理完毕,SAPI也准备关闭了,PHP开始执行第二步:
PHP调用每个扩展的MSHUTDOWN方法,这是各个模块最后一次释放内存的机会。 一个典型的RSHUTDOWN方法如下:PHP_MSHUTDOWN_FUNCTION(extension_name) {/* Free handlers and persistent memory etc */} 这样,整个PHP生命周期就结束了。要注意的是,只有在服务器没有请求的情况下才会执行“启动第一步”和“关闭第二步”。
图1 php结构
从图上可以看出,php从下到上是一个4层体系
①Zend引擎
Zend整体用纯c实现,是php的内核部分,它将php代码翻译(词法、语法解析等一系列编译过程)为可执行opcode的处理并实现相应的处理方法、实现了基本的数据结构(如hashtable、oo)、内存分配及管理、提供了相应的api方法供外部调用,是一切的核心,所有的外围功能均围绕zend实现。
②Extensions
围绕着zend引擎,extensions通过组件式的方式提供各种基础服务,我们常见的各种内置函数(如array系列)、标准库等都是通过extension来实现,用户也可以根据需要实现自己的extension以达到功能扩展、性能优化等目的(如贴吧正在使用的php中间层、富文本解析就是extension的典型应用)。
③Sapi
Sapi全称是Server Application Programming Interface,也就是服务端应用编程接口,sapi通过一系列钩子函数,使得php可以和外围交互数据,这是php非常优雅和成功的一个设计,通过sapi成功的将php本身和上层应用解耦隔离,php可以不再考虑如何针对不同应用进行兼容,而应用本身也可以针对自己的特点实现不同的处理方式。后面将在sapi章节中介绍
④上层应用
这就是我们平时编写的php程序,通过不同的sapi方式得到各种各样的应用模式,如通过webserver实现web应用、在命令行下以脚本方式运行等等。
构架思想:
引擎(Zend)+组件(ext)的模式降低内部耦合
中间层(sapi)隔绝web server和php
**************************************************************************
如果php是一辆车,那么
车的框架就是php本身
Zend是车的引擎(发动机)
Ext下面的各种组件就是车的轮子
Sapi可以看做是公路,车可以跑在不同类型的公路上
而一次php程序的执行就是汽车跑在公路上。
因此,我们需要:性能优异的引擎+合适的车轮+正确的跑道
把php最终集成到Apache系统中,还需要对Apache进行一些必要的设置。这里,我们就以php的mod_php5 SAPI运行模式为例进行讲解,至于SAPI这个概念后面我们还会详细讲解。
假定我们安装的版本是Apache2 和 Php5,那么需要编辑Apache的主配置文件http.conf,在其中加入下面的几行内容:
Unix/Linux环境下:
LoadModule php5_module modules/mod_php5.so
AddType application/x-httpd-php .php
注:其中modules/mod_php5.so 是X系统环境下mod_php5.so文件的安装位置。
Windows环境下:
LoadModule php5_module d:/php/php5apache2.dll
AddType application/x-httpd-php .php
注:其中d:/php/php5apache2.dll 是在Windows环境下php5apache2.dll文件的安装位置。
这两项配置就是告诉Apache Server,以后收到的Url用户请求,凡是以php作为后缀,就需要调用php5_module模块(mod_php5.so/ php5apache2.dll)进行处理。
Apache请求处理循环详解 Apache请求处理循环的11个阶段都做了哪些事情呢?
1、Post-Read-Request阶段
在正常请求处理流程中,这是模块可以插入钩子的第一个阶段。对于那些想很早进入处理请求的模块来说,这个阶段可以被利用。
2、URI Translation阶段 Apache在本阶段的主要工作:将请求的URL映射到本地文件系统。模块可以在这阶段插入钩子,执行自己的映射逻辑。mod_alias就是利用这个阶段工作的。
3、Header Parsing阶段 Apache在本阶段的主要工作:检查请求的头部。由于模块可以在请求处理流程的任何一个点上执行检查请求头部的任务,因此这个钩子很少被使用。mod_setenvif就是利用这个阶段工作的。
4、Access Control阶段 Apache在本阶段的主要工作:根据配置文件检查是否允许访问请求的资源。Apache的标准逻辑实现了允许和拒绝指令。mod_authz_host就是利用这个阶段工作的。
5、Authentication阶段 Apache在本阶段的主要工作:按照配置文件设定的策略对用户进行认证,并设定用户名区域。模块可以在这阶段插入钩子,实现一个认证方法。
6、Authorization阶段 Apache在本阶段的主要工作:根据配置文件检查是否允许认证过的用户执行请求的操作。模块可以在这阶段插入钩子,实现一个用户权限管理的方法。
7、MIME Type Checking阶段 Apache在本阶段的主要工作:根据请求资源的MIME类型的相关规则,判定将要使用的内容处理函数。标准模块mod_negotiation和mod_mime实现了这个钩子。
8、FixUp阶段 这是一个通用的阶段,允许模块在内容生成器之前,运行任何必要的处理流程。和Post_Read_Request类似,这是一个能够捕获任何信息的钩子,也是最常使用的钩子。
9、Response阶段 Apache在本阶段的主要工作:生成返回客户端的内容,负责给客户端发送一个恰当的回复。这个阶段是整个处理流程的核心部分。
10、Logging阶段 Apache在本阶段的主要工作:在回复已经发送给客户端之后记录事务。模块可能修改或者替换Apache的标准日志记录。
11、CleanUp阶段 Apache在本阶段的主要工作:清理本次请求事务处理完成之后遗留的环境,比如文件、目录的处理或者Socket的关闭等等,这是Apache一次请求处理的最后一个阶段。
一个好的框架应该是灵活的、低耦合的,所以配置系统是重要的也是必需的。ThinkPHP提供的配置核心都是基于PHP数组的。在ThinkPHP中,配置文件都是自动加载的(也就是不用显示require),加载顺序为:默认配置->公共配置->模式配置->调试配置->场景配置->模块配置->扩展配置->动态配置。加载顺序优先级从左往右依次递增,也就是说“动态配置”是最高优先级,如果左边的配置和右边有重复,系统会使用右边的值。
默认配置是ThinkPHP“大道至简,开发由我”宗旨的核心体现,旨在减少开发的编码工作而设计的。默认情况下,该配置文件路径为ThinkPHP/Conf/convention.php,对于一个新的Web项目,,除了数据库配置可能要自定义之后,几乎不需要额外的配置定义。所谓公共配置,指的是一个应用下的所有模块都会加载的配置文件。默认情况下,公共配置的文件路径为Application/Common/Conf/config.php。针对配置的操作无非读写而已,ThinkPHP提供了很方便的配置操作函数C(大写字母C)。ThinkPHP按照默认的顺序加载完配置之后,配置全局有效,在框架作用范围内(一般指应用目录下),所有配置都可以直接使用C函数读取(包括ThinkPHP默认配置)。作为配置操作的一个重要函数,不得不单独提下C函数。打开文件ThinkPHP/Common/functions.php,可以看到C函数定义如下:
可以看到ThinkPHP的注释是很详尽的,就算是没有使用过C函数的程序员,看完注释之后对C函数的使用方法应该是没有问题的。C语言函数算法说明如下:
(1)定义static $_config变量,static方式定义的变量本次请求内全局有效。
(2)如果传入的$name为空,返回所有配置;如果不为空,进入第3步。
(3)判断$name是否为字符串,如果是,进入第4步;否则进入第12步。
(4)判断$name中是否有“.”,如果没有,进入第5步;否则进入第8步。
(5)将$name转换为大写,如果$value为null,进入第6步;否则进入第7步。
(6)判断是否存在名为$name的配置,如果存在,则返回该配置的值;否则返回默认值。
(7)将名称为$name的配置值设为$value,并返回null。
(8)将$name分割为数组,加入传入的$name为“user.name”,分割完之后$name为['user','name']。
(9)将$name数组的第1个元素“user”转换为大写,如果传入的$value为null,则进入第10步,负责进入第11步。
(10)判断是否存在$_config[$name[0]][$name[1]](本例中为$_config['user']['name'])的配置,如果存在,返回$_config[$name[0]][$name[1]]的值,否则返回null。
(11)将名称为$_config[$name[0]][$name[1]](本例中为$_config['user']['name'])的配置值设为$value,并返回null。
(12)如果$name是数组,则将该数组的全部键名转换为大写后合并到全局配置中去。
(13)最后返回null是为了防止非法调用函数。
通过源码分析发现,ThinkPHP的配置名称只有一级是不区分大小写的,也就是说C(‘DATA_CACHE_TYPE’)和C(‘data_cache_type’)的返回值是相等的,但是二级配置是区分大小写的,也就是说C(‘user.name’)和C(‘user.NAME’)是不相等的。另外,关于无限级配置,因为源码中可以看到ThinkPHP在对配置的处理只处理到二级,不支持二级以上配置。
本篇文章主要给大家介绍PHP stubstr()函数的用法,substr()是PHP中的内置函数,用于提取字符串的一部分,即返回字符串的子串。
语法:
substr(string_name, start_position, string_length_to_cut)
参数:
substr()函数允许三个参数,其中两个是强制的,一个是可选的。
string_name:在这个参数中,我们传递原始字符串或需要剪切或修改的字符串。这是一个强制参数。
start_position:如果 start_position是非负数,返回的字符串将从 string 的 start 位置开始,从 0 开始计算。如果 start_position是负数,返回的字符串将从 string 结尾处向前数第 start 个字符开始。这也是一个强制参数。
string_length_to_cut:此参数是可选的,为整数类型。这指的是需要从原始字符串中剪切的字符串部分的长度。如果整数是正数,则它指的是从start_position开始并从头开始提取长度。如果整数是负数,那么它指的是从start_position开始并从字符串的结尾提取长度。如果未传递此参数,则substr()函数将返回从start_position开始直到字符串结尾的字符串。
返回类型:
如果成功则返回提取的字符串部分;如果失败,返回FALSE或空字符串。
PHP substr()函数的用法示例:
<?phpfunction Substring($str){$len = strlen($str); echo substr($str, 6), "<br>"; echo substr($str, 3, $len), "<br>"; echo substr($str, -11, 11), "<br>"; echo substr($str,-11, -8), "<br>";}$str="phpAndmysql";Substring($str);
输出:
mysqlAndmysqlphpAndmysqlphp
本文来自PHP中文网,更多相关知识点请前往PHP中文网视频课程频道!
ThinkPHP框架常用的是MVC模式,M是模型、V是视图,C是控制器。通过MVC模式将数据从数据库中查询出来,然后传递到页面中。下面我们来说一下具体的情况;
程序一、视图渲染
模板定位规则:当前模块/view/当前控制器名(小写)/当前操作(小写).html。在5.1.6版本后系统会以简洁模式定位模板文件位置,规则如下:当前模块/view/当前控制器(小写)_当前操作(小写).html
1、Fetch方法
fetch方式是渲染模板时最常用的方法,在使用此方法的前提是控制器类需要继承系统控制器基础类。使用方式如下:
(1)、不需要传递任何参数,框架会自动定位到模板文件;
return $this->fetch();
(2)、传递一个参数,框架会定位至当前控制器下的参数一模板文件;
return $this->fetch('edit');
(3)、传递两个参数,框架会定位至参数一控制器下的参数二模板文件;
return $this->fetch('member/read');
注意事项:在书写参数时请不要书写任何后缀,参数只是目录名称或文件名称而已。
(4)、视图根目录下文件
如果想把view文件夹内的单独文件进行渲染,可以在参数位置进行如下书写:
return $this->fetch('/menu');
(5)、特殊模板文件或特殊位置文件
如果项目中存在特殊模板文件,又不想移动位置,可以通过如下方式进行调用:
return $this->fetch('./template/menu.html');
上面书写的目录位置是相对于当前项目入口文件位置(public目录),模板文件后缀无固定要求,可以为html、php、tpl等格式
PHP代码2、助手函数方式
如果控制器未继承系统基础控制器类,同样可以实现视图模板的输出,框架提供了助手函数view(),可以使用如下命令:
return view();
可传递参数及数据,常见的使用方式如下:
return view('模板文件路径','数据');
3、直接解析模板方式
项目中某些页面可能通过直接解析模板的方式就可以实现功能,那么我们可以通过最简单的方式对模板文件进行输出。使用如下命令:
return $this->display();
此方式会直接渲染内容,同样模板标签在视图中可以正常使用。
HTML模板二、视图赋值
1、assign方法
在继承系统基础控制器类后可以通过如下命令进行视图赋值:
$this->assign("名","值");
批量赋值方式:
$this->assign(['名'=>'值','名'=>'值']);
2、方法传入参数方式
此方式在进行视图渲染中提及到了,通过设置模板文件位置时携带数据。命令如下:
$this->fetch('path',['名'=>'值','名'=>'值']);$this->display('path',['名'=>'值','名'=>'值']);
3、助手函数赋值方式
这种方式是项目开发过程中最常见的模式,助手函数无需继承基础控制类,相对而言代码更加精简、可读性更高。命令如下:
return view('path',['名'=>'值','名'=>'值']);
4、公共模板变量赋值方式
可以使用视图类的share静态方法进行全局公共模板变量赋值。命令如下:
use think\facade\View;// 赋值全局模板变量View::share('name','value');// 或者批量赋值View::share(['name1'=>'value','name2'=>'value2']);
视频过滤三、视图过滤
1、局部过滤
在单独方法内进行视图过滤操作。命令如下:
// 使用视图输出过滤return $this->filter(function($content){returnstr_replace("\r\n",'<br/>',$content);})->fetch();
2、全局过滤
如果进行全局过滤方式,需要在初始化方法中进行设置。命令如下:
protected functioninitialize(){$this->view->filter(function($content){returnstr_replace("\r\n",'<br/>',$content); });}
总结:视图过滤方式可以理解过对视图模板中内容进行了替换操作,可以通过此方式减少代码空行,无用的缩进。减少代码体积。
四、模板引擎
框架中内置了模板引擎,默认可以忽略对此进行设置,同时框架支持自定义引擎模式。在配置目录(config目录)下的template.php文件中可进行配置。
默认提供了两种扩展引擎:think-angular、twig(都不是很完美,不建议使用
4、)
五、扩展
如果只想获得解析文件而不进行渲染,如果生成静态HTML文件,采用纯静态化模式。可以使用如下命令:
$html = $this->fetch()->getContent();
此方式返回字符串,可以继承文件创建方式,批量生成HTML静态文件,便于网站优化。
六、总结
1、依据场景,选择不同的渲染方式;
2、合理的进行模板赋值;
3、牢记特殊模板文件位置是基础项目入口文件位置;
4、模板文件配置目录为:config/template.php文件;
在开发过程中,我们需要写控制器、模型、验证代码。最后要写模板代码,如果是前后端分离项目则不用写模板了。直接在接口中返回数据就可以了。模板代码包含了很多知识,下面举例介绍一下;
代码变量输出
1、常见的输出方式是使用大括号({ })的形式,里面写入变量名称。在runtime/temp目录下可以看到编译后的文件,括号解析成了<?php ?>的形式,并且里面包含htmlentities。命令如下(注意$ 和 { 之间不能存在空格):
{$data}
2、原样解析,如果解析富文本内容时使用,使用示例:
{$data|raw}
3、默认值,使用示例:
{$data|default='这是一个默认值'}
4、系统变量输出,主要是获取用户昵称,使用示例:
{$Think.session.name}
5、常量输出,使用示例:
{$Think.PHP_VERSION}
6、配置输出,主要是获取基础网址,使用示例:
{$Think.config.default_module}
PHP使用函数
1、框架内置规则:
2、应用方式:
2.1、单函数应用,使用示例:
{$data.name|md5}
2.2、多函数应用,使用示例:
{$name|md5|upper|substr=0,3}
互联网开发运算符
1、常见运算符
2、三元运算符
2.1、默认写法
{$status?'正常':'错误'}
2.2、简单写法,表示有则输出,无则输出默认值
{$name ??'默认值'}
2.3、为真写法,表示为真的时候才输出默认值
{$name?='默认值'}
2.3、真假写法、表示为真输出值,否则输出默认值
{$name ?:'NO'}
2.4、表达式写法,表达式为真则输出值一,否则输出值二
{$a==$b ?'yes':'no'}
程序代码原样输出
原样输出使用较少,如果想让输出内容不被模板标签所解析,使用如下命令进行输出:
{literal} Hello,{$name}!{/literal}
模板注释
模板注释和代码注释是两种方式,模板注释不会在页面上查看到被注释的代码,而代码注释则可以查看的到。使用方式如下:
{/* 这是模板注释内容*/} 或 {// 这是模板注释内容 }
模板布局
模板布局总结来说就两点:配置和模板;
配置分为模块配置和应用配置,一般情况下后台多应用模板布局方式,在后台模块config/template.php文件内(默认不存在,需手动创建)设置如下代码:
'layout_on'=>true, //开启布局模式'layout_name'=>'layout', //布局文件名称,可设置为 'index/layout'目录形式'layout_item'=>'{__REPLACE__}' //输出替换变量
模板继承
在实际项目开发过程中使用较少,主要是因为继承过于麻烦。
包含文件
在实际项目开发过程中,前端页面使用较多,使用方式较为单一;
1、使用模版文件,多个文件使用逗号分隔;
{include file="public/header,public/menu"/}
2、传入参数,此方式需注意模板中变量值必须存在;
{include file="Public/header" keywords="开源WEB开发框架"/}
开发代码输出替换
1、配置,在应用或模块配置目录下的template.php文件中进行如下代码配置:
'tpl_replace_string'=>['__STATIC__'=>'/static','__JS__'=>'/static/javascript',]
2、总结,优点:方便更改;但是不建议使用,建议在开发过程中设置好目录位置。
标签库
标签库类似于Java的Struts中的JSP标签库,每一个标签库是一个独立的标签库文件,标签库中的每一个标签完成某个功能,采用XML标签方式(包括开放标签和闭合标签)。具体内容请参考官方文档。
内置标签
1、普通循环标签,使用示例:
{volist name="list" id="vo" key="k"}{$k}.{$vo.name}{/volist}
如果没有指定key属性的话,默认使用循环变量i
2、控制输出行数,如输出其中的第5~15条记录,使用示例:
{volist name="list" id="vo" offset="5" length='10'}{$vo.name}{/volist}
3、比较标签(不常用)
4、SWITCH标签(不常用),使用示例:
{switch User.level} {case 1}value1{/case} {case 2}value2{/case} {default /}default {/switch}
5、资源文件加载(常用),使用实例:
{load href="/static/js/common.js,/static/css/style.css"/}
互联网标签扩展
此扩展在开发过程中并不常用,使用起来较为麻烦。
数据加密在我们生活中的地位已经越来越重要了,尤其是考虑到在网络上发生的大量 交易和传输的大量数据。如果对于采用安全措施有兴趣的话,也一定会有兴趣了解PHP提供的一系列安全功能。在本篇文章中,我们将介绍这些功能,提供一些基本的用法,以便你能够为自己的应用软件中增加安全功能。
预备知识
在详细介绍PHP的安全功能之前,我们需要花点时间来向没有接触过这方面内容的读者介绍一些有关密码学的基本知识,如果对密码学的基本概念已经非常熟悉,就可以跳 过去这一部分。 密码学可以通俗地被描述为对加/解密的研究和实验,加密是将易懂的资料转换为不易懂资料的过程,解密 则是将不易懂的资料转换为原来易懂资料的过程。不易懂的资料被称作密码,易懂的资料被称作明码。 数据的加/解密都需 要一定的算法,这些算法可以非常地简单,如著名的凯撒码,但当前的加密算法要相对复杂得多,其中一些利用现有的方法甚至是无法破译的 。
PHP的加密功能只要有一点使用非Windows平台经验的人可能对crypt()也相当熟悉,这一函数完成被称作单向加密 的功能,它可以加密一些明码,但不能够将密码转换为原来的明码。尽管从表面上来看这似乎是一个没有什么用处的功能,但它的确被广泛用 来保证系统密码的完整性。因为,单向加密的口令一旦落入第三方人的手里,由于不能被还原为明文,因此也没有什么大用处。在验证用户输 入的口令时,用户的输入采用的也是单向算法,如果输入与存储的经加密后的口令相匹配,则输入的口信一定是正确的。PHP同样提供了使用其crypt()函数完成单向加密功能的可能性。我将在这里简要地介绍该函数:
string crypt (string input_string [, string salt])
其中的input_string参数是需要加密的字符串,第二个可选的salt是一个位字串,它能够影响 加密的暗码,进一步地排除被称作预计算攻击的可能性。缺省情况下,PHP使用一个2个字符的DES干扰串,如果你的系统使用的是MD5(我将在 以后介绍MD5算法),它会使用一个12个字符的干扰串。顺便说一下,可以通过执行下面的命令发现系统将要使用的干扰串的长度:
print "My system salt size is: ". CRYPT_SALT_LENGTH;
系统也可能支持其他的加密算法。crypt()支持四 种算法,下面是它支持的算法和相应的salt参数的长度:
算法 Salt长度 CRYPT_STD_DES 2-character (Default) CRYPT_EXT_DES 9-character CRYPT_MD5 12-character beginning with $ CRYPT_BLOWFISH 16-character beginning with $ 用crypt()实现用户身份验证 作为crypt()函数的一个例子,考虑这样一种情况,你希望创建一段PHP脚本程序限 制对一个目录的访问,只允许能够提供正确的用户名和口令的用户访问这一目录。我将把资料存储在我喜欢的数据库MySQL的一个表中。下面我 们以创建这个被称作members的表开始我们的例子: mysql>CREATE TABLE members ( ->username CHAR(14) NOT NULL, ->password CHAR(32) NOT NULL, ->PRIMARY KEY(username) ->);
mysql>CREATE TABLE members ( ->username CHAR(14) NOT NULL, ->password CHAR(32) NOT NULL, ->PRIMARY KEY(username) ->);
然后,我们假定下面的数据已经存储在该表中: 用户名 密码 clark keloD1C377lKE bruce ba1T7vnz9AWgk peter paLUvRWsRLZ4U 这些加密的口令对应的明码分别是kent、banner和parker。注意一下每个口令的前二个字母, 这是因为我使用了下面的代码,根据口令的前二个字母创建干扰串的:
$enteredPassword. $salt = substr($enteredPassword, 0, 2); $userPswd = crypt($enteredPassword, $salt); // $userPswd然后就和用户名一起存储在MySQL 中
我将使用Apache的口令-应答认证配置提示用户输入用户名和口令,一个鲜为人知的有关PHP的信息是,它可以把Apache 的口令-应答系统输入的用户名和口令识别为$PHP_AUTH_USER和$PHP_AUTH_PW,我将在身份验证脚本中用到这二个变量。花一些时间仔细阅读下 面的脚本,多注意一下其中的解释,以便更好地理解下面的代码: crypt()和Apache的口令-应答验证系统的应用
$host = "localhost"; $user = "zorro"; $pswd = "hell odolly"; $db = "users"; // Set authorization to False $authorization = 0; // Verify that user has entered username and password if (isset($PHP_AUTH_USER) &&isset($PHP_AUTH_PW)) : mysql_pconnect($host, $user, $pswd) or die("Can't connect to MySQL server!"); mysql_select_db($db) or die("Can't select database!"); // Perform the encryption $salt = substr($PHP_AUTH_PW, 0, 2); $encrypted_pswd = crypt($PHP_AUTH_PW, $salt); // Build the query $query = "SELECT username FROM members WHERE username = '$PHP_AUTH_USER' AND password = '$encrypted_pswd'"; // Execute the query if (mysql_numrows(mysql_query($query)) == 1) : $authorization = 1; endif; endif; // confirm authorization if (! $authorization) : header('WWW-Authenticate: Basic realm="Private"'); header('HTTP/1.0 401 Unauthorized'); print "You are unauthorized to enter this area."; exit; else : print "This is the secret data!"; endif; >
上面就是一个核实用户访问权限的简单身份验证系统。在使用crypt()保护重要的机密资料时,记住在缺省状态下使用的 crypt()并不是最安全的,只能用在对安全性要求较低的系统中,如果需要较高的安全性能,就需要我在本篇文章的后面介绍的算法。 下面我将介绍另一个PHP支持的函数━━md5(),这一函数使用MD5散列算法,它有几种很有趣的用法值得一提:
混编一个混编函数可以将一个可变长度的信息变换为具有固定长度被混编过的输出,也被称作“信息文摘”。这是十分有用的,因为 一个固定长度的字符串可以用来检查文件的完整性和验证数字签名以及用户身份验证。由于它适合于PHP,PHP内置的md5()混编函数将把一个可 变长度的信息转换为128位(32个字符)的信息文摘。混编的一个有趣的特点是不能通过分析混编后的信息得到原来的明码,因为混编后的结果 与原来的明码内容没有依赖关系。 即便只改变一个字符串中的一个字符,也将使得MD5混编算法计算出二个截然不同的结果。我们首先来看下 表的内容及其相应的结果: 使用md5()混编字符串
$msg = "This is some message that I just wrote"; $enc_msg = md5($msg); print "hash: $enc_msg ";
结果: hash: 81ea092649ca32b5ba375e81d8f4972c 注意,结果的长度为32个字符。再来看一下下面的表,其中的$msg的值有了一点 微小的变化: 使用md5()对一个稍微变化的字符串进行混编
//注意,message中少了一个s $msg = "This is some mesage that I just wrote"; $enc_msg = md5($msg); print "hash2: $enc_msg ";
结果: hash2: e86cf511bd5490d46d5cd61738c82c0c 可以 发现,尽管二个结果的长度都是32个字符,但明文中一点微小的变化使得结果发生了很大的变化,因此,混编和md5()函数是检查数据中微小变 化的一个很好的工具。 尽管crypt()和md5()各有用处,但二者在功能上都受到一定的限制。在下面的部分中,我们将介绍 二个非常有用的被称作Mcrypt和Mhash的PHP扩展,将大大拓展PHP用户在加密方面的选择。 尽管我们在上面的小节中说明了 单向加密的重要性,但有时我们可能需要在加密后,再把密码数据还原成原来的数据,幸运的是,PHP通过Mcrypt扩展库的形式提供了这种可能 性。 Mcrypt Mcrypt 2.5.7 Unix | Win32 Mcrypt 2.4.7是一个功能强大的加密算法扩展库,它包括有22种算法 ,其中就包括下面的几种算法: Blowfish RC2 Safer-sk64 xtea Cast-256 RC4 Safer-sk128 DES RC4-iv Serpent Enigma Rijndael-128 Threeway Gost Rijndael-192 TripleDES LOKI97 Rijndael-256 Twofish PanamaSaferplus Wake
安装: 在标准的PHP软件包中不包括Mcrypt,因此需要下载它,下载后,按照下面的方法进行编译,并把它扩充在PHP中:
gunzipmcrypt-x.x.x.tar.gz tar -xvfmcrypt-x.x.x.tar./configure --disable-posix-threads makemake installcd to your PHP directory. ./configure -with-mcrypt=[dir] [--other-configuration-directives] makemake install
当然了,根据你的 要求和PHP安装时与互联网服务器软件的关系,上面的过程可能需要作适当的修改。
使用Mcrypt Mcrypt的优点不仅仅 在于其提供的加密算法较多,还在于它可以对数据进行加/解密处理,此外,它还提供了35种处理数据用的函数。尽管对这些函数进行详细介绍 已经超出了这篇文章的范围,我还是要就几个典型的函数作一下简要的介绍。 首先,我将介绍如何使用Mcrypt扩展库对数 据进行加密,然后再介绍如何使用它进行解密。下面的代码对这一过程进行了演示,首先是对数据进行加密,然后在浏览器上显示加密后的数 据,并将加密后的数据还原为原来的字符串,将它显示在浏览器上。 使用Mcrypt对数据进行加、解密
// Designate string to be encrypted $string = "Applied Cryptography, by Bruce Schneier, is a wonderful cryptography reference."; // Encryption/decryption key $key = "Four score and twenty years ago"; // Encryption Algorithm $cipher_alg = MCRYPT_RIJNDAEL_128; // Create the initialization vector for added security. $iv = mcrypt_create_iv(mcrypt_get_iv_size($cipher_alg, MCRYPT_MODE_ECB), MCRYPT_RAND); // Output original string print "Original string: $string"; // Encrypt $string $encrypted_string = mcrypt_encrypt($cipher_alg, $key, $string, MCRYPT_MODE_CBC, $iv); // Convert to hexadecimal and output to browser print "Encrypted string: ".bin2hex($encrypted_string).""; $decrypted_string = mcrypt_decrypt($cipher_alg, $key, $encrypted_string, MCRYPT_MODE_CBC, $iv); print "Decrypted string: $decrypted_string";
执行上面的脚本将会产生下面的输出: Original string: Applied Cryptography, by Bruce Schneier, is a wonderful cryptography reference. Encrypted string: 02a7c58b1ebd22a9523468694b091e60411cc4dea8652bb8072 34fa06bbfb20e71ecf525f29df58e28f3d9bf541f7ebcecf62b c89fde4d8e7ba1e6cc9ea24850478c11742f5cfa1d23fe22fe8 bfbab5e Decrypted string: Applied Cryptography, by Bruce Schneier, is a wonderful cryptography reference. 上面的代码中二个最典型的函数是mcrypt_encrypt()和 mcrypt_decrypt(),它们的用途是显而易见的。我使用了“电报密码本”模式,Mcrypt提供了几种加密方式,由于每种加密方式都有可以影响 密码安全的特定字符,因此每种模式都需要了解。对于没有接触过密码系统的读者来说,可能对mcrypt_create_iv()函数更有兴趣,尽管对这 一函数进行彻底的解释已经超出了本篇文章的范围,但我仍然会提到它创建的初始化向量(hence, iv),这一向量可以使每条信息彼此独立。 尽管不是所有的模式都需要这一初始化变量,但如果在要求的模式中没有提供这一变量,PHP就会给出警告信息。
Mhash扩展库 0.8.3版的Mhash扩展库支持12种混编算法,仔细检查Mhash v.0.8.3的头文件mhash.h可以知道,它支持下面的混编算法: CRC32 HAVAL160 MD5 CRC32B HAVAL192 RIPEMD160 GOST HAVAL224 SHA1 HAVAL128 HAVAL256 TIGER
安装 象Mcrypt一 样,Mhash也没有包括在PHP软件包中,对于非Windows用户而言,下面是安装过程: 下载Mhash扩展库
gunzipmhash-x.x.x.tar.gz tar -xvfmhash-x.x.x.tar./configuremakemake installcd./configure -with-mhash=[dir] [--other-configuration-directives] makemake install
象Mcrypt一样 ,根据PHP在互联网服务器软件上的安装方式,可能需要对Mhash进行其他的配置。
使用Mhash 对信息进行混编非常简单,看一下下面的例子:
$hash_alg = MHASH_TIGER; $message = "These are the directions to the secret fort. Two steps left, three steps right, and cha chacha."; $hashed_message = mhash($hash_alg, $message); print "The hashed message is ". bin2hex($hashed_message);
执行这一段脚本程序将得到下面的输出结果:
The hashed message is 07a92a4db3a4177f19ec9034ae5400eb60d1a9fbb4ade461
在这里使用bin2hex()函数的目的是方便我们理解$hashed_message 的输出,这是因为混编的结果是二进制格式,为了能够将它转化为易于理解的格式,必须将它转换为十六进制格式。 需要 注意的是,混编是单向功能,其结果不依赖输入,因此可以公开显示这一信息。这一策略通常用于让用户比较下载文件和系统管理员提供的文 件,以确保文件的完整性。 Mhash还有其他一些有用的函数。例如,我需要输出一个Mhash支持的算法的名字,由于 Mhash支持的所有算法的名字都以MHASH_开头,因此,可以通过执行如下的代码完成这一任务:
$hash_alg = MHASH_TIGER; print "This data has been hashed with the".mhash_get_hash_name($hashed_message)."hashing algorithm.";
得到的输出是: This data has been hashed with the TIGER hashing algorithm. 关于PHP和加密最后需要注意的一个问题 关于PHP和加密需要注意的最后的一个重要问题是在服务器和客户端之间传输的数据 在传输过程中是不安全的!PHP是一种服务器端技术,不能阻止数据在传输过程中泄密。因此,如果想实现一个完整的安全应用,建议选用 Apache-SSL或其他的安全服务器布置。
结论这篇文章介绍了PHP最有用的功能之一━━数据加密,不仅讨论了PHP内置 的crypt() 和md5()加密函数,还讨论了用于数据加密的功能强大的扩展库━━Mcrypt和Mhash。在这篇文章最后,我需要指出的是,一个真正安全的PHP应用还应该包括安全的服务器,由于PHP是一种服务器端的技术,因此,在数据由客户端向服务器端进行传输时,它不能保证数据的安全。
路由是开发过程中比较重要的一环,在ThinkPHP5.1版本后路由默认开启,并且不可以关闭,足以可见它的重要性。下面我们来具体的说一下;
注意事项
1、默认开启、不可关闭;
2、优先匹配、多模式支持;
3、匹配成功,不再继续匹配;
4、默认支持数字、字母、下划线,不支持中文及特殊符号;
PHP主要作用
1、URL链接更加规范、美观,更加适合SEO优化;
2、隐式传入额外请求参数;
3、请求方式拦截,区分GET、POST等请求方式;
4、绑定请求数据;
5、处理请求缓存,优化程序响应时间;
6、路由中间件支持(V5.1.6+版本以上支持);
SEO优化路由定义
1、定义位置:route/route.php文件内,可以在route目录内多文件定义,最终框架会进行路由整合,建议采用域名+分组模式定义路由。
2、定义方式:
Route::get('new/:id','News/read');// 定义GET请求路由规则Route::post('new/:id','News/update');// 定义POST请求路由规则Route::put('new/:id','News/update');// 定义PUT请求路由规则Route::delete('new/:id','News/delete');// 定义DELETE请求路由规则Route::any('new/:id','News/read');// 所有请求都支持的路由规则
请注意:
1、路由匹配成功后,原链接访问方式会失效;
2、完全匹配需在尾部添加$ ;
3、变量可有可无使用[] 包裹变量;
变量规则
系统默认的变量规则设置是\w+,只会匹配字母、数字和下划线字符,并不会匹配特殊符号和中文,需要定义变量规则或者调整默认变量规则。
1、局部配置(仅在当前路由有效)
*定义GET请求路由规则 并设置name变量规则
Route::get('new/:name','News/read')->pattern(['name'=>'\w+']);
2、全局配置(全部路由有效)
*设置name变量规则(采用正则定义)
Route::pattern('name','\w+');
*支持批量添加
Route::pattern(['name'=>'\w+','id'=>'\d+',]);
3、组合变量
*组合变量的优势是路由规则中没有固定的分隔符,可以随意组合需要的变量规则和分割符
Route::get('item-<name>-<id>','product/detail')->pattern(['name'=>'\w+','id'=>'\d+']);
PHP框架路由地址
闭包支持
实际开发过程中不常用,是一种简单直接的定义模式;
Route::rule('hello/:name',function(Request $request, $name){$method = $request->method();return'['. $method .'] Hello,'. $name;});
路由参数
互联网开发路由缓存
在定义大量的路由时,强烈建议使用路由缓存,注意仅在部署模式下有效,开启该缓存可以明显提升路由解析性能。
开启方式,在应用配置文件app.php中设置开启:
'route_check_cache'=>true,
开启后,会自动对每次的路由请求的调度进行缓存,第二次如果是相同的请求则无需再次经过路由解析,而是直接进行请求调度。
清除命令:
>php think clear --route
跨域请求
如果某个路由或者分组需要支持跨域请求,可以使用如下代码:
Route::get('new/:id','News/read')->ext('html')->allowCrossDomain();
注解路由
此方式不建议使用,缺点路由分散不方便管理,同时书写规则要求较为严格。
代码路由分组
强烈建议使用,下面书写一种比较完善的路由分组写法:
Route::group(['method'=>'get','ext'=>'html'],function(){Route::group('blog',function(){Route::rule('blog/:id','blog/read');Route::rule('blog/:name','blog/read');});})->pattern(['id'=>'\d+','name'=>'\w+']);
MISS路由
如果希望在没有匹配到所有的路由规则后执行一条设定的路由,可以注册一个单独的MISS路由,总结来说,可以应用于404页面,防止程序找不到路由而报错(一旦设置了MISS路由,相当于开启了强制路由模式);
Route::miss('public/miss');
资源路由
实际开发过程中不常用,不做描述。
快捷路由
此方式要求在控制器层面定义方法名称较为严格,简单做一下描述,不建议使用。
*给User控制器设置快捷路由
Route::controller('user','index/User');<?php namespace app\index\controller;class User{public functiongetInfo(){ }}
代码路由别名
路由别名不支持变量类型和路由条件判断,单纯只是为了缩短URL地址,并且在定义的时候需要注意避免和路由规则产生混淆。设置操作方法的请求类型:
*user 别名路由到 index/user 控制器
Route::alias('user','index/user',['ext'=>'html','allow'=>'index,save,delete','method'=>['index'=>'GET','save'=>'POST','delete'=>'DELETE'],]);
路由绑定
把当前的URL绑定到模块/控制器/操作,最多支持绑定到操作级别,例如在路由配置文件中添加:
*绑定当前的URL到 index模块
Route::bind('index');
*绑定当前的URL到 index模块的blog控制器
Route::bind('index/blog');
域名路由
支持完整域名、子域名和IP部署的路由和绑定功能,同时还可以起到简化URL、加快匹配的作用。
Route::domain(['blog','admin'],function(){Route::rule('new/:id','index/news/read');});
URL生成
支持路由URL地址的统一生成,并且支持所有的路由方式,但是不建议使用,直接在页面中手动设置,减少模板解析时间。
可以使用助手函数url,不需要继承框架基础控制器类即可使用,示例如下:
url('index/blog/read','id=5&name=thinkphp');
解析后为:/index.php/blog/5/name/thinkphp.html
其他配置方式不做过多讲解。请移步官方文档查看。
一、打开关闭文件
1、fopen()函数打开文件,它有两个参数第一个是文件名,第二个是打开方式。
// 获取文件路径 $filePath = "psg.txt"; // 打开文件,将资源绑定到一个流或者句柄,绑定之后,脚本就可以通过句柄与此资源交互。 $fileHandle = fopen($filePath, "a+");
fopen()函数第二个参数可能的值
mode
说明
r只读方式打开,文件从头开始读。
r+读写方式打开,文件从头开始读写。
w只写方式打开文件,从文件开头开始写。如果文件已经存在,将文件指针指向文件头并将文件大小截为零,即删除所有文件已有的内容,如果文件不存在,函数将创建这个文件。
w+读写方式打开文件,如果文件已经存在,将文件指针指向文件头并将文件大小截为零。即删除所有文件已有的内容,如果文件不存在,函数将创建这个文件。
a写入方式打开,将文件指针指向文件末尾。如果该文件已有内容,将从文件末尾开始追加,如果该文件不存在,函数将创建这个文件。
a+读写方式打开,将文件指针指向文件末尾。如果该文件已有内容,将从文件末尾开始追加或者读,如果该文件不存在,函数将创建这个文件。
作者:XZ阳光小熊链接:https://www.jianshu.com/p/e845ab9e85c6來源:简书简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
PHP面向对象
前言
学习PHP的小朋友们都知道,PHP在中小型企业的应用是非常广泛包括建站、小程序、CRM与OA等,那么作为基础中的基础,PHP面向对象你又掌握了多少呢?在这将就这个问题做一个详细的讲解。
正文
一、定义类 使用关键字class定义
二、实例化对象 使用关键字new实例化对象
三、类成员的添加和访问 (1)类成员:属性、方法、常量 (2)添加成员需要使用修饰符 public、protected、private (3)修饰符的作用范围 public 类内类外子类 protected 类内子类 private 类内 (4)添加方法:如果方法前不带修饰符,默认带public; (5)添加常量:const 常量名; 访问常量:类名::常量名; ::范围解析操作符
四、类内部对象$this和内存原理
$this是一个对象,指向实例化对象。当我们new实例化的时候,系统会给这个对象分配一个内存空间,内存空间分为栈内存和堆内存,将变量存在栈里,代码块存在堆里,然后堆的内存地址指向栈里的变量,如果再给栈中的变量赋值引用数据类型,内存地址就会被改变。
五、如果$a和$p指向同一个内存地址,它们是同一个对象,则改变一个则两个都会变
需要用克隆解决这个问题 关键字clone;通过clone来复制一个一模一样的对象,这样它们就不是同一个对象了;
六、构造函数和析构函数
(1)构造函数:我们在声明类的时候就存在这个函数,用new实例化时,函数自动调用。public function __construct(){};(2)析构函数:用于释放new实例化的内存空间,如果不销毁,会增加系统性能负荷;new实例化时,系统会自动调用;销毁原则:先人后出。
七、静态成员
静态成员的添加:在成员属性或方法前加关键字 static; 静态成员的访问: 内部使用:self::$变量;或 类名::$变量; 外部使用: 类名::$变量;
八、面向对象的三大特征
(1)封装:对外只提供可操作的方法,不会告诉你内部结构;(2)继承 子类可以继承父类的属性和方法,但是是有限继承,public、protected、private三个修饰的属性都可以继承,public、protected两个修饰的方法可以继承,父类的常量可以继承;(3)多态:php没有多态。重载:当子类跟父类有个相同的方法时,子类的方法会覆盖父类的方法。
九、关键字:parent
在继承中的子类有parent,可以访问父类的常量、方法、父类的静态属性,属性成员不能访问;访问方式: parent::$静态属性、fn()、常量。
十、final 不可重载的
(1)写在类前面 不许类被继承;(2)写在方法和属性前 子类不能重载父类的方法。
十一、抽象类 abstract
(1)抽象类不能被实例化;(2)如果一个类里面有一个方法被声明为抽象类,这个类就得申明抽象类;(3)只要这个方法被声明为抽象方法了,就不能写函数体,将函数后面的{}去掉,函数体由子类实现;(4)在继承一个抽象类的时候,子类必须定义父类。
结尾
通过本文的讲解各位对于PHP面向对象是不是有了一个基本的了解,想要熟练掌握还需要你们平时多下苦工与多多的联系。