函数
// 匿名函数也叫做闭包函数,允许临时创建一个没有指定名称的函数,最经常用作回调函数参数的值。
类与对象
// 1.类的定义class SimpleClass{ // 声明属性 public $var = 'a default value'; // 声明方法 public function displayVar() { echo $this -> var }}/*$this说明假如类的对象去调用类里定义的方法,那么这个$this就是这个对象,如果是类去使用的话,那么这个$this是没有值的。关于$this,在php5和php7中有部分是不一样的假如有两个对象(a,b),这两个对象对应的类是不一样的,一个对象(a)里的方法调用了另一个类(b对象的类)里的方法,那个类里的方法有一个$this这个属性,那么此时这个$this的值应该是什么呢?1.在php5中,这个$this就是a这个对象2.在php7中,这个$this是没有值的*/// 对象的创建,也就是类的实例$zhuyu = new People();// 也可以这样$className = 'People';$zhuyu = new $classNanme();// 对象赋值$zhuyu = new $People();$zhuchunyu = $zhuyu;$zhu = &$zhuyu;$zhuyu -> var = 'var';$zhuyu = null;var_dump($zhuyu); // 输出值为nullvar_dump($zhu); // 输出值为nullvar_dump($zhuchunyu); // 有输出值/*简化上面的结论,大概就是这样一段代码$b = $a;$c = &$a;$a = null;首先$b = $a;这行代码就是一个普通的赋值,那么$b所对应的$a所对应的值的内存地址,它和$a是是没有丝毫关系的再看$c = &$a;这是引用赋值吧,所以说$c对应的值的内存地址和$a所对应的值的内存地址是息息相关的,它是跟着$a所变换的最后$a = null;这也是一个普通的赋值,那么$a对应的是null的内存地址,之前$c的值是个$a的值是有关系的,所以$c也变成了null,$b的内存地址还是对应之前的内存地址。*/// 创建新对象class Test{ static public function getNew() { return new static; }}class Child extends Test{}$obj1 = new Test();$obj2 = new $obj1;var_dump($obj1 !== $obj2); // ture$obj3 = Test::getNew();var_dump($obj3 instanceof Test);$obj4 = Child::getNew();var_dump($obj4 instanceof Child);/*方式一:通过new一个类去创建一个对象方式二:通过调用类里的方法,创建一个新对象*//*对象属性属性声明是由关键字开头:public protected private访问非静态属性方式:->访问静态属性方式:::*/// 类常量class A { const constant = 'constant value';}// 构造方法 __construct() 相当于python中的__init__()class People extends BaseClass{ function __construct() { // 实力对象之前,先执行偶 print '创建一个实例,先执行__construct'; $this -> name = '朱春宇' // 调用父类的__construct(), parent::__construct(); }}// 析构函数 __destruct 相对于python中 __del__方法// 在删除一个对象之前,会先执行__destruct方法class Test{ function __destruct(){ print 'del'.$this -> name . '\n' }}// 访问控制(可见性)/*对属性或者方法的访问控制,是通过在前面添加关键字public(公有),protected(受保护),pricate(私有)来实现的public:可以在任何地方都可以被访问protected:可以被自身及其子类和父类访问private:只能被它所在的类才能访问private相当于python中封装的思想,只能在类内部使用。*/// 对象继承 extends/*子类继承父类,会继承父类所有的共有方法,受保护的方法,子类也可以重写父类的方法。*/// 范围解析操作符(::)/*可以用来访问静态成员,类常量,还可以用于覆盖类的属性的方法和属性比如调用父类的方法 parent::__construct*/// 静态关键字(static)/*声明类的属性或方法为静态,就可以不实例化类而直接访问,静态属性是不能通过类实例的对象去访问的,而静态方法是可以的访问静态属性和方法的方法都是::*/// 抽象类实例abstract class Test{ // 强制要求子类定义这些方法 abstract public function getValue(); abstract public function prefixValue(); // 非抽象方法 public function foo(){ print '非抽象方法foo'; } }class Test1 extends Test{ public function getValue() { // getvalue方法代码 } public function prefixValue(){ // prxfixValue方法代码 }}/*对于抽象类的理解:1.和python中abc库差不多,控制子类的一些方法属性,必须有。2.达到上面抽象类的效果,也可以通过主动抛异常去实现,在父类定义一个函数,直接抛异常,如果继承他的类没有重写该方法,在使用到这个方法的时候,便会执行父类的方法,直接抛异常。*/// 对象接口/*可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容接口是通过interface关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的接口中定义的所有方法都必须是公有,这就是接口的特性*/// 声明一个'iTemplate'接口interface iTemplate{ public function setVariable($name,$var); public function getHtml($template);}// 实现接口class Template implements iTemplate{ private $vars = array(); public function setVariable($name,$var) { $this -> vars[$name]=$var; } public function getHtml($template) { foreach($this->vars as $name=>$var){ $template = str_replace('{'.$name.'}',$value,$template); } return $template; }}// 接口之间的继承,interface a{ public function faa();}interface b extends a{ public function fbb();}class c implements b{ // 这个c如果想要实现a,b接口,那么必须要有a,b接口里的所有方法 public function faa(); public function fbb();}/*抽象类与接口之间相同之处和不同之处1.相同点- 两者都是抽象类,不能进行实例化- interface实现类及abstract class的子类都必须实现已经声明的抽象方法2.不同点- 接口实现需要implements,抽象类实现需要继承(extends)- 接口中声明的方法都必须是public(公有的),而抽象类声明的方法(这个方法带有abstract),可以是public,protected,但绝不能是private。如果抽象类中的方法是public类型的话,那么继承它的类的这个方法必须是public,如果抽象类中的方法是protected类型,那么继承它的类的方法应该是public或者protected类型。- 接口中声明的方法,只能是方法名,方法里面不能有代码块。抽象类中声明的方法可以有- 一个类可以实现多个接口,但是只能继承一个抽象类*/// trait 一种代码复用的方法tarit speak { public function speakHello(){ print 'hello'."\n"; } $name = 'zhuyu';}class A{ $name = 'zhuchunyu';}class B extends A{ use speak;}b = new B();print b->name;// 匿名类/*比如一些函数需要的参数需要传递类,那么可以直接new 类名()*/// 重载:/*定义:是指动态地创建类属性和方法,我们是通过魔法方法来实现注意:1.所有重载方法都必须声明为public 2.这些魔法方法的参数都不能通过引用传递 3.php中的重载与其他绝大多数面向对象语言不同。传统的“重载”是用于提供多个同名的类方法,但各方法的参数类型和个数不同*/// 属性重载/*- 在给不可访问属性赋值时,__set(%name,$value)会被调用。- 读取不可访问属性的值时,__get(%name)会别调用。- 当对不可访问属性调用isset()或empty()时,__isset()会被调用。- 当对不可访问属性调用unset()时,__unset()会被调用。*/// 方法重载/*- __call:在对象中调用一个不可访问的方法时,被调用- __callStatic:在静态上下文中调用一个不可访问方法时,被调用*/// 遍历对象 foreachclass A{ public $name = '朱宇'; public $age = 18; public $sex = '男'; protected $top = '1.71'; private $a = 'aa'; public function myForEach() { foreach ($this as $key=>$value){ echo $key.'='.$value."\n"; } }}$a = new A();foreach ($a as $item=>$value){ echo $item.'='.$value."\n";}$a->myForEach();/*- 外面这个foreach的输入结果是没有protected,private的值的- 函数内部里的foreach可以显示所有的属性的- foreach它只能循环它能访问的属性*/// 魔法方法/*1.__construct(),它会在new一个对象之前触发执行2.__destruct(),它会在del一个对象之前,运行。3.__call,它会在调用一个方法,并且这个方法不存在的时候执行4.__callStatic,它会在调用一个静态方法,并且这个方法不存在的时候执行5.__get(),获取一个对象的属性,并且这个属性不存在的话,那么便会执行这个魔法方法6.__set(),再给对象的一个属性赋值时,并且这个属性不能访问,那么就会执行这个方法7.__isset,执行isset()函数的时候,先执行8.__unset,执行unset()函数的时候,先执行9.__sleep(),在执行serialize()这个函数的时候,会检查类中是否存在该魔法方法,有的话,会先调用__sleep()这个方法,然后在执行序列化操作。这个方法的返回值应该是一个数组,如果这个方法没有返回值的话,那么null则会被序列化,并且产生一个E_noteic级别的错误。10.__wakeup(),会在执行unserialize这个函数的,会先执行该魔法方法。11.__toString(),这个方法在打印一个对象的时候,自动触发,返回值必须是字符串,和python中的__str__12.__invoke(),当尝试以调用函数的方法调用一个对象时,__invoke()自动触发,和python中__call__13.__set_state(),14.__clone(),15.__debuginfo(),16.__autoload(),*/// final关键字// 如果父类中的方法被声明为final,则子类无法覆盖该方法,如果一个类被声明为final,则不能被继承// final方法示例class BaseClass{ public function faa(){ print 'faa'."\n"; } final public function fbb(){ print 'fbb'."\n"; }}class AClass extends BaseClass{ public function fbb(){ print 'AClass fbb'."\n"; }}$a = new AClass();$a->fbb();// final类实例final class BaseClass{ public $name;}class AClass extends BaseClass{}$a = new AClass();echo $a ->name;// 对象复制 __clone方法class SubObject{ static $instances = 0; public $instance; public function __construct() { $this->instance = ++self::$instances; } public function __clone() { $this->instance = ++self::$instances; }}class MyCloneable{ public $object1; public $object2; function __clone() { // 强制复制一份this->object, 否则仍然指向同一个对象 $this->object1 = clone $this->object1; }}$obj = new MyCloneable();$obj->object1 = new SubObject();$obj->object2 = new SubObject();$obj2 = clone $obj;print("Original Object:\n");print_r($obj);print("Cloned Object:\n");print_r($obj2);/*上面的打印的效果为 $obj -> object1为 1 ,$obj -> object2为 2 $obj2 -> object1为 3 ,$obj -> object2为 2 首先__clone方法只有调用clone这个方法,才会去执行在执行$obj2 = clone $obj这行代码之前,$obj这个对象的的属性值为 object1为1,object2为2,在执行$obj2 = clone $obj这行代码的时候,首先会去执行$obj这个对象里的__clone方法,这个$obj是类MyCloneable的对象,那么就去看这个类里的__clone方法,这个方法执行这行代码$this->object1 = clone $this->object1;首先会执行clone $this->object1这行代码,$this->object1对应的是SubObject类的对象,便会执行该类里的__clone方法,此时$instances的值为2,那么执行__clone之后的话,$instance的值就是3了,最终的代码为 $this->object1 = 一个SubObject的对象,对象里$instance的值为3。*/// 对象比较/*1.使用(==)双等号进行比较的话,比较的原则是:如果两个对象的属性和属性值都相等,并且两个对象是同一个实例,那么这两个对象变量相等。2.如果使用(===)全等符号,这两个对象变量一定要指向某个类的同一个实例(即同一个对象)思考 $a=$b它是怎么个过程,$a,$b都是一个对象*/// 类型约束:在方法或者函数的参数之前,加一个类型,就是对参数的类型约束了。// 后期静态绑定/*用法:self::对当前类的静态引用,__CLASS__是当前对象的类名 static:: parent::执行器父类的方法*/// 对象和引用/*关于这行代码 $a = $b,($b只是一个类的对象),在php的对象编程中,我觉得就是引用传递,$a,$b它们指向的内置地址都是同一个,所有一旦其中一个改变属性,对应的它对应的内存地址的值发生改变,所有另一个变量也会进行改变。*/// 对象序列化/*php里面的值,都可以使用函数serialize()来返回一个包含字节流的字符串来表示,unseralize()函数则是能够把字符串重新转换为原来的php值。序列化一个对象会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字*/