-
函数
// 匿名函数也叫做闭包函数,允许临时创建一个没有指定名称的函数,最经常用作回调函数参数的值。
-
类与对象
// 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); // 输出值为null var_dump($zhu); // 输出值为null var_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 . ' ' } } // 访问控制(可见性) /* 对属性或者方法的访问控制,是通过在前面添加关键字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'." "; } $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:在静态上下文中调用一个不可访问方法时,被调用 */ // 遍历对象 foreach class 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." "; } } } $a = new A(); foreach ($a as $item=>$value){ echo $item.'='.$value." "; } $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'." "; } final public function fbb(){ print 'fbb'." "; } } class AClass extends BaseClass { public function fbb(){ print 'AClass fbb'." "; } } $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: "); print_r($obj); print("Cloned Object: "); 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值。序列化一个对象会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字 */