0x06 函数/类/对象
php的函数和c/c++的非常相似
php的函数通常分为两种,用户自定义函数和系统函数
function foo($arg_1, $arg_2, /* ..., */ $arg_n) { echo "Example function.\n"; return $retval; }
上面就是用户自定义的函数
我们也可以自定义匿名函数
匿名函数(Anonymous functions),也叫闭包函数(closures),允许 临时创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值。当然,也有其它应用的情况。
<?php $greet = function($name) { printf("Hello %s\r\n", $name); }; $greet('World'); $greet('PHP'); ?>
关于匿名函数,可以使用use来传递外部的变量,而且传递变量引用也和普通的传递变量引用一致
php的引用函数必须在定义和使用的时候都加上&才能生效,否则就是普通的函数
<?php class foo { public $value = 42; public function &getValue() { return $this->value; } } $obj = new foo; $myValue = &$obj->getValue(); // 42 $obj->value = 2; echo $myValue; // 2.
如果上面的改成$myValue = $obj->getValue(); 下面打印的结果也将是42
关于类
每个类的定义都以关键字 class 开头,后面跟着类名,后面跟着一对花括号,里面包含有类的属性与方法的定义。
php中可以使用public protected private 控制成员的访问
关于类的自动加载 建议使用spl_autoload_register() 如果类名比如被用于 call_user_func(),则它可能包含一些危险的字符,比如 ../。 建议您在这样的函数中不要使用用户的输入,但是有时候我们必须用到这个函数,这时候我们一定要过滤和验证一下输入的合法性.
类的自动加载常用在框架中
关于构造函数和析构函数
php中使用void __construct ([ mixed $args [, $... ]] ) 作为构造函数 (早期的版本只能使用与类相同的名字的构造函数,自 PHP 5.3.3 起,在命名空间中,与类名同名的方法不再作为构造函数。这一改变不影响不在命名空间中的类。) void __destruct ( void ) 作为析构函数
关于继承
继承已为大家所熟知的一个程序设计特性,PHP 的对象模型也使用了继承。继承将会影响到类与类,对象与对象之间的关系。比如,当扩展一个类,子类就会继承父类所有公有的和受保护的方法。除非子类覆盖了父类的方法(尽量不要覆盖父类的方法,这可能造成混乱从而引发不可预知的错误,请谨慎使用),被继承的方法都会保留其原有功能。继承对于功能的设计和抽象是非常有用的,而且对于类似的对象增加新功能就无须重新再写这些公用的功能。
范围解析操作符(也可称作 Paamayim Nekudotayim)或者更简单地说是一对冒号,可以用于访问 静态 成员, 类常量 ,还可以用于覆盖类中的属性和方法。我们可以使用parent:: 来访问父类中被覆盖的方法关于重载
PHP所提供的"重载"(overloading)是指动态地"创建"类属性和方法。是通过魔术方法(magic methods)来实现的。
当调用当前环境下未定义或不可见的类属性或方法时,重载方法会被调用。本节后面将使用"不可访问属性(inaccessible properties)"和"不可访问方法(inaccessible methods)"来称呼这些未定义或不可见的类属性或方法。
所有的重载方法都必须被声明为 public。
在给不可访问属性赋值时,__set() 会被调用。
读取不可访问属性的值时,__get() 会被调用。
当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用。
当对不可访问属性调用 unset() 时,__unset() 会被调用。
参数 $name 是指要操作的变量名称。__set() 方法的 $value 参数指定了 $name 变量的值。
属性重载只能在对象中进行。在静态方法中,这些魔术方法将不会被调用。所以这些方法都不能被 声明为 static。从 PHP 5.3.0 起, 将这些魔术方法定义为 static 会产生一个警告。
关于static
声明类属性或方法为静态,就可以不实例化类而直接访问。静态属性不能通过一个类已实例化的对象来访问(但静态方法可以)。
为了兼容 PHP 4,如果没有指定访问控制,属性和方法默认为公有。
由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用。
静态属性不可以由对象通过 -> 操作符来访问。
用静态方式调用一个非静态方法会导致一个 E_STRICT 级别的错误。
就像其它所有的 PHP 静态变量一样,静态属性只能被初始化为文字或常量,不能使用表达式。所以可以把静态属性初始化为整数或数组,但不能初始化为另一个变量或函数返回值,也不能指向一个对象。
自 PHP 5.3.0 起,可以用一个变量来动态调用类。但该变量的值不能为关键字 self,parent 或 static。
当我们重写static方法时,我们实际使用的还是父类的static方法,即运行时最初调用
后期静态绑定本想通过引入一个新的关键字表示运行时最初调用的类来绕过限制。简单地说,这个关键字能够让你在上述例子中调用 test() 时引用的类是 B 而不是 A。最终决定不引入新的关键字,而是使用已经预留的 static 关键字。
<?php class A { public static function who() { echo __CLASS__; } public static function test() { static::who(); // 后期静态绑定从这里开始 } } class B extends A { public static function who() { echo __CLASS__; } } B::test(); ?>以上例程会输出:
B关于抽象类和抽象方法
PHP 5 支持抽象类和抽象方法。定义为抽象的类不能被实例化。任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。
继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。此外方法的调用方式必须匹配,即类型和所需参数数量必须一致。例如,子类定义了一个可选参数,而父类抽象方法的声明里没有,则两者的声明并无冲突。 这也适用于 PHP 5.4 起的构造函数。在 PHP 5.4 之前的构造函数声明可以不一样的。
关于接口
使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。
接口是通过 interface 关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的。
接口中定义的所有方法都必须是公有,这是接口的特性。
要实现一个接口,使用 implements 操作符。类中必须实现接口中定义的所有方法,否则会报一个致命错误。类可以实现多个接口,用逗号来分隔多个接口的名称。
Note:
实现多个接口时,接口中的方法不能有重名。
Note:
接口也可以继承,通过使用 extends 操作符。
Note:
类要实现接口,必须使用和接口中所定义的方法完全一致的方式。否则会导致致命错误。
接口中也可以定义常量。接口常量和类常量的使用完全相同,但是不能被子类或子接口所覆盖。
抽象类和接口在使用上有一定的相似点,但他们使用的场景会有所不同 如果要创建一个模型,这个模型将由一些紧密相关的对象采用,就可以使用抽象类。如果要创建将由一些不相关对象采用的功能,就使用接口。 如果必须从多个来源继承行为,就使用接口。如果知道所有类都会共享一个公共的行为实现,就使用抽象类,并在其中实现该行为。自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait。
Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用 method。Trait 和 Class 组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。
Trait 和 Class 相似,但仅仅旨在用细粒度和一致的方式来组合功能。 无法通过 trait 自身来实例化。它为传统继承增加了水平特性的组合;也就是说,应用的几个 Class 之间不需要继承。
这个相对比较复杂,需要更详细解释
关于匿名类
PHP 7 开始支持匿名类。 匿名类很有用,可以创建一次性的简单对象。
// 使用了 PHP 7+ 后的代码 $util->setLogger(new class { public function log($msg) { echo $msg; } });
可以传递参数到匿名类的构造器,也可以扩展(extend)其他类、实现接口(implement interface),以及像其他普通的类一样使用 trait:
<?php class SomeClass {} interface SomeInterface {} trait SomeTrait {} var_dump(new class(10) extends SomeClass implements SomeInterface { private $num; public function __construct($num) { $this->num = $num; } use SomeTrait; }); PHP 5 提供了一种定义对象的方法使其可以通过单元列表来遍历,例如用 foreach 语句。默认情况下,所有 可见 属性都将被用于遍历。
对象与类是php中比较复杂的部分,可以多花一些时间进行了解熟悉
