- 介绍
- 本地环境安装
- 安装 WNMP 环境
- 代码编辑器选择
- 语法
- 变量与常量
- 常见输出函数
- 数据类型之四种标量类型
- 数据类型之三种复合类型
- 数据类型之两种特殊类型
- Operators:运算符
- 流程控制:条件判断语句
- 流程控制:循环语句
- 流程控制:中止语句
- 函数
- 类和对象:基本概念
- 类和对象:类结构
- 类和对象:面向对象
- 类和对象:三种特殊类
- 类和对象
- 类和对象:Trait
- 类和对象:魔术方法
- 命名空间
- 【实战】PHP表单
-
String
- addcslashes()
- addslashes()
- bin2hex()
- chop()
- chr()
- chunk_split()
- convert_cyr_string()
- convert_uudecode()
- convert_uuencode()
- count_chars()
- crc32()
- crypt()
- echo
- explode()
- fprintf()
- get_html_translation_table()
- hebrev()
- hebrevc()
- hex2bin()
- htmlentities()
- htmlspecialchars()
- htmlspecialchars_decode()
- html_entity_decode()
- implode()
- join()
- lcfirst()
- levenshtein()
- localeconv()
- ltrim()
- md5()
- md5_file()
- metaphone()
- money_format()
- nl2br()
- nl_langinfo()
- number_format()
- ord()
- parse_str()
- printf
- quoted_printable_decode()
- quoted_printable_encode()
- quotemeta()
- rtrim()
- setlocale()
- sha1()
- sha1_file()
- similar_text()
- soundex()
- sprintf()
- sscanf()
- strcasecmp()
- strchr()
- strcmp()
- strcoll()
- strcspn()
- stripcslashes()
- stripos()
- stripslashes()
- strip_tags()
- stristr()
- strlen()
- strnatcasecmp()
- strnatcmp()
- strncasecmp()
- strncmp()
- strpbrk()
- strpos()
- strrchr()
- strrev()
- strripos()
- strrpos()
- strspn()
- strstr()
- strtok()
- strtolower()
- strtoupper()
- strtr()
- str_getcsv()
- str_ireplace()
- str_pad()
- str_repeat()
- str_replace()
- str_rot13()
- str_shuffle()
- str_split()
- str_word_count()
- substr()
- substr_compare()
- substr_count()
- substr_replace()
- trim()
- ucfirst()
- ucwords()
- vfprintf()
- vprintf()
- vsprintf()
- wordwrap()
-
Array
- array()
- array_change_key_case()
- array_chunk()
- array_column()
- array_combine()
- array_count_values()
- array_diff()
- array_diff_assoc()
- array_diff_key()
- array_diff_uassoc()
- array_diff_ukey()
- array_fill()
- array_fill_keys()
- array_filter()
- array_flip()
- array_intersect()
- array_intersect_assoc()
- array_intersect_key()
- array_intersect_uassoc()
- array_intersect_ukey()
- array_keys()
- array_key_exists()
- array_key_first()
- array_key_last()
- array_map()
- array_merge()
- array_merge_recursive()
- array_multisort()
- array_pad()
- array_pop()
- array_product()
- array_push()
- array_rand()
- array_reduce()
- array_replace()
- array_replace_recursive()
- array_reverse()
- array_search()
- array_shift()
- array_slice()
- array_splice()
- array_sum()
- array_udiff()
- array_udiff_assoc()
- array_udiff_uassoc()
- array_uintersect()
- array_uintersect_assoc()
- array_uintersect_uassoc()
- array_unique()
- array_unshift()
- array_values()
- array_walk()
- array_walk_recursive()
- arsort()
- asort()
- compact()
- count()
- current()
- each()
- end()
- extract()
- in_array()
- key()
- key_exists()
- krsort()
- ksort()
- list()
- natcasesort()
- natsort()
- next()
- pos()
- prev()
- range()
- reset()
- rsort()
- shuffle()
- sizeof()
- sort()
- uasort()
- uksort()
- usort()
-
File
- basename()
- chgrp()
- chmod()
- chown()
- clearstatcache()
- copy()
- dirname()
- diskfreespace()
- disk_free_space()
- disk_total_space()
- fclose()
- feof()
- fflush()
- fgetc()
- fgetcsv()
- fgets()
- fgetss()
- file()
- fileatime()
- filectime()
- filegroup()
- fileinode()
- filemtime()
- fileowner()
- fileperms()
- filesize()
- filetype()
- file_exists()
- file_get_contents()
- file_put_contents()
- flock()
- fnmatch()
- fopen()
- fpassthru()
- fputcsv()
- fputs()
- fread()
- fscanf()
- fseek()
- fstat()
- ftell()
- ftruncate()
- fwrite()
- glob()
- is_dir()
- is_executable()
- is_file()
- is_link()
- is_readable()
- is_uploaded_file()
- is_writable()
- is_writeable()
- lchgrp()
- lchown()
- link()
- linkinfo()
- lstat()
- mkdir()
- move_uploaded_file()
- parse_ini_file()
- parse_ini_string()
- pathinfo()
- pclose()
- popen()
- readfile()
- readlink()
- realpath()
- realpath_cache_get()
- realpath_cache_size()
- rename()
- rewind()
- rmdir()
- set_file_buffer()
- stat()
- symlink()
- tempnam()
- tmpfile()
- touch()
- umask()
- unlink()
-
Datetime
- checkdate()
- date()
- date_add()
- date_create()
- date_create_from_format()
- date_date_set()
- date_default_timezone_get()
- date_default_timezone_set()
- date_diff()
- date_format()
- date_get_last_errors()
- date_interval_create_from_date
- date_interval_format()
- date_isodate_set()
- date_modify()
- date_offset_get()
- date_parse()
- date_parse_from_format()
- date_sub()
- date_sunrise()
- date_sunset()
- date_sun_info()
- date_timestamp_get()
- date_timestamp_set()
- date_timezone_get()
- date_timezone_set()
- date_time_set()
- getdate()
- gettimeofday()
- gmdate()
- gmmktime()
- gmstrftime()
- idate()
- localtime()
- microtime()
- mktime()
- strftime()
- strptime()
- strtotime()
- time()
- timezone_abbreviations_list()
- timezone_identifiers_list()
- timezone_location_get()
- timezone_name_from_abbr()
- timezone_name_get()
- timezone_offset_get()
- timezone_open()
- timezone_transitions_get()
- timezone_version_get()
-
Filter
-
HTTP
-
cURL
- curl_close()
- curl_copy_handle()
- curl_errno()
- curl_error()
- curl_escape()
- curl_exec()
- curl_file_create()
- curl_getinfo()
- curl_init()
- curl_multi_add_handle()
- curl_multi_close()
- curl_multi_errno()
- curl_multi_exec()
- curl_multi_getcontent()
- curl_multi_info_read()
- curl_multi_init()
- curl_multi_remove_handle()
- curl_multi_select()
- curl_multi_setopt()
- curl_multi_strerror()
- curl_pause()
- curl_reset()
- curl_setopt()
- curl_setopt_array()
- curl_share_close()
- curl_share_errno()
- curl_share_init()
- curl_share_setopt()
- curl_share_strerror()
- curl_strerror()
- curl_unescape()
- curl_version()
-
PDO
-
PDOStatement
类和对象:Trait
在前面几节的学习中,我们清楚了类和对象的概念、结构,面向对象的基本思想和特殊的三个类以及接口的定义与使用,这些特性在许多编程语言中都是普遍存在的,接下来的这节则是 PHP 专为单继承语言(类只能继承一个类)设计的代码复用机制:Trait。
我们已经知道,PHP 是一门单继承语言,单继承意味着一个类只能继承一个类,这在有时候是受限的:在不同结构层次的互不关联的类中无法复用方法。在PHP 5.4的时候,解决了这个问题——Trait
面世了。
定义一个Trait
使用关键字trait
即可,语法如下:
trait Traitable {
// 代码
}
Trait的用法
Trait
与类很像,它不能像普通类一样实例化,但它拥有类的许多特点。下面我们来看一下Trait
可以做什么:
<?php
// Trait
trait tBase
{
// Trait 可定义属性
public $val;
public function getThis()
{
// Trait 所定义的方法必须包含实现
return $this;
}
protected function perameter()
{
// Trait 对于方法的可见性没有限制
}
// Trait 支持定义抽象方法(使用Trait的类同样必须实现抽象方法)
abstract public function abstractFunc();
static public function staticFunc()
{
// Trait 可定义静态方法
}
}
trait tSub
{
use tBase;
}
class Base
{
// 使用 Trait
use tSub;
// 实现 Trait 中的抽象方法
public function abstractFunc()
{
echo 'Trait中定义的抽象方法必须在使用了Trait的类中实现',"\n";
}
}
class Other
{
use tSub;
// 实现 Trait 中的抽象方法
public function abstractFunc()
{
echo 'Trait中定义的抽象方法必须在使用了Trait的类中实现',"\n";
}
}
// 测试:Trait 中获取的 $this 会指向使用该Trait的类
$base = new Base();
var_dump($base);
/* 输出:
object(Base)#1 (1) {
["val"]=>
NULL
}
*/
$base->abstractFunc();// 输出:Trait中定义的抽象方法必须在使用了Trait的类中实现
$other = new Other();
var_dump($base->getThis());
/* 输出:
object(Base)#1 (1) {
["val"]=>
NULL
}
*/
var_dump($other->getThis());
/* 输出:
object(Other)#2 (1) {
["val"]=>
NULL
}
*/
可以看出Trait
与类结构别无二致!
Trait
除了不能像普通类一样被实例化,还有一点和类不同的是,Trait可以随意组合:class
可以使用Trait
,Trait
也可以使用Trait
,只要使用关键字use
声明。
“可随意组合”意味着Trait
可以在各种类中重复使用而不用考虑继承问题,Trait就像一块砖,哪儿有用往哪儿搬。
也意味着我们的类可以拆分出一部分描述其需求和功能的代码,作为具有某特点的Trait
。但这并不是说发现两个类中两段代码一样就提取到一起,一切从功能或需求出发。
Trait的特征性
Trait
翻译过来就是特征、特性,在有些书里也把它叫做性状
。我们暂且将它看做“特征”好了。
特征可以理解为在一群类似的对象中,某一个对象拥有不一样的特点。这样一想笔者第一反应是丑小鸭与白天鹅的故事。当然这里不会讲童话故事,我们只是把这个故事作为案例:
在“丑小鸭与白天鹅”的故事里,小白鹅与小黄鸭都属于禽类,有着一身的羽毛,会说话(并不),但是小白鹅会飞,小黄鸭不行。
这样一分析,运用前面所学的知识,我们大概可以设计出三个类:禽类作为基类,有着禽类的基本特征:羽毛(这里只列出一部分),会叫。小白鹅和小黄鸭分别作为禽类的子类,小白鹅类实现“会飞”的方法,小黄鸭类没有。
这样并没有错。
但是如果再添加一个不一样的对象呢?老鹰。这三者都是禽类,但是小白鹅和老鹰都会飞,小黄鸭和小白鹅都会游泳。按照上面的思考方式,我们可能会做两种方案:
- 禽类作为基类,小白鹅、小黄鸭和老鹰分别是它的子类,小白鹅和老鹰实现“会飞”的方法,小白鹅和小黄鸭实现“会游”的方法
- 听上去没毛病,但这里造成了代码重复使用
- 禽类作为基类,“会飞的禽类”是它的子类,小白鹅和老鹰继承“会飞的禽类”,小黄鸭则继承禽类,独自实现“会游”的方法
- 听上去也没毛病,也把重复代码去掉了。但这里多了一个基类
在可区分的特性越来越多时,PHP 的单继承性需要让我们设计许多基类,层层继承,最后得到一个拥有各种特性的类,想想上面的例子,如果再加一个“会迁徙”的大雁呢?
这时候我们就可以用到 PHP 的Trait
。
同一类对象可能拥有多种性征,而多类对象可能拥有相同性征,这种情况就适用于Trait
。
将每个特征(会飞的、会游的、会迁徙的)都提取出来,然后在类中使用它们!上面的例子使用代码表达就是:
<?php
// 禽类
class Bird
{
public $feather;// 羽毛
public function howl()
{
// 啼叫
}
}
// Trait
trait Fly
{
public function fly()
{
// 飞行
echo '我会飞',"\n";
}
}
trait Swimming
{
public function swimming()
{
// 凫水
echo '我会游泳',"\n";
}
}
trait Migrate
{
public function migrate()
{
// 迁徙
echo '我会迁徙',"\n";
}
}
// 继承基类的子类,并使用相应的Trait
class Duck { use Swimming; }
class Swan { use Fly, Swimming; }
class Eagle { use Fly; }
class Goose { use Fly, Migrate; }
// 测试:
$duck = new Duck();
$duck->swimming();
// $duck->fly();// 未定义,不能使用
$goose = new Goose();
$goose->fly();
$goose->migrate();
这样一看是不是很清晰?子类各自具备的特征一目了然。
如果按照一层一层继承的方法,很容易迷失在臃肿的结构中,而且不方便解耦。比如说想要去除某一个特性,而这个特性被嵌套在深深的类继承中,“牵一发而动全身”说的就是这种情况。
而使用Trait
的话,只需要删掉这个特性的使用即可。
合理使用Trait
我们已经知道Trait
的优势,那是不是遇到重复代码就提取为Trait
呢?
当然不是,Trait不仅仅是可复用代码段的集合,更是某个特性的属性和方法的一段描述。通常Trait
被命名为“xxable”,表示“可做某某事”(上述示例中三个Trait都没有able
后缀的版本故而没有遵循这个命名规则),用以体现Trait
的用途。
示例代码并没有涉及太多属性,但经常一些特征是伴随着独特的属性一起出现的,例如上面的“迁徙”方法,可以添加两个属性:迁徙的时间和迁徙的地点。这两个属性仅跟“迁徙”这个方法相关,与“大雁”类没有太大关联,那么在“拆分”代码时可以把属性和方法一起“打包”到Trait
。
本节阐述了 Trait 的基本使用和特点,并分析了它的适用情况。现在进行总结:
- 使用上
Trait
与类结构相似,只是不能被实例化- 使用关键字
trait
定义 Trait
可定义属性、抽象方法、静态方法和普通方法Trait
和类都可以使用关键字use
使用Trait
- 优势
- 相比于类,
Trait
可随意组合 Trait
逻辑清晰,可读性高Trait
耦合性低,可复用性高
- 相比于类,
截至本节,关于类和对象的所有主要概念都已结束!最后一节为扩展说明,讲述了类和对象中的魔术方法。