欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

php代码之面向对象基础一

程序员文章站 2024-01-03 11:44:16
...
这篇文章不适合于初学者看,对php有一定了解的可以看一下,补充或者温故一下php面向对象里的一些特性。


一.何为面向对象?

介个问题,虽然略知一二,却感觉依然拿不出手,只能说将万事万物皆看为对象,只有在开发中才能体会出何为面向对象,只说也是徒然,但因为php大多用在web开发,所以,即使不使用面向对象也能运行的不错,之前在做c++开发时,设计给你个功能界面,看到这个界面,第一件事就是像美工切图一样的切成一个个的对象,然后,确定各个对象之间的关系,最后进行开发,哪儿都充斥着此思想。

什么是类?什么是对象?

类是一组集合的抽象,什么集合呢?是一组具有相似特性和操作的对象的集合。

对象是某一个类的具体实例。

毕业时候可能我会背给面试官听,可现在,虽然感觉理解的还是想书本上的语句一样的俗,但起码不用再靠脑细胞说出这两个定义。


二.php中的类结构

php中类也是那些访问控制符,也是有属性和方法。

class Person {    private $name = "PersonName";    public static $gender = "PersonGender";        public function test(){        echo $this->name, '
'; }};


三.构造函数

构造函数的名称为__construct,在构造函数这里我想强调的有以下几点:

1. php不会像其他语言(c++或者java)那样,当实例化子类的时候会自动调用你的父类构造函数,php里需要手动调用父类的构造函数,这儿牵扯到继承,可以先看一下继承方面的东西。

class Person{	public funciton __construct(){		echo 'Person construct
'; }};class Teacher extends Person{ public function __construct(){ //parent::__construct(); echo 'Teacher construct
'; }};$t1 = new Teacher; //生成Teacher对象

运行结果:

Teacher construct

如果想要在生成子类时初始化父类的一些数据,需要手动调用父类的构造函数,打开注释行即可。


2. 一个类中不能写两个参数不同的构造函数。

这儿牵扯到php中的一些规定,其他语言中,以下写法是正确的:

class Person{	public funciton __construct(){		echo 'Person construct
'; } public function __construct($param){ echo 'Person with param construct
'; }};


而在php是不允许的,究其根源为php是一种弱语言类型,对于类型的限制不是很敏感,进而提供了__call和func_get_args函数机制,因而可以用如下的方式实现:

class Person{	public function __construct(){		$param = func_get_arg(); //获取参数数据		$param_num = func_num_args(); //获取参数个数		if($param_num == 0){		}else if($param_num == 1){			if(is_array($param[0])){				//...			}		}else{			//...		}	}};


三.析构函数

析构函数是用于在此实例对象结束时,自动调用的函数,可以写入一下释放内存的语句来为实例的死亡画上完美的句号,这儿与构造相同,有继承关系时必须手动调用父类的析构,一个类中只有一个析构。


四.控制访问符

public:公共访问符,在类内,子类内,类外都可以访问此属性或方法。

protected:受保护的访问符,只能在类内和其子类内访问此属性或方法,在类外不能访问。

private:私有访问符,只能在本类内访问,属于本类私有东东,不能继承,不能重载,任何人访问不了。


五.魔术方法__get和__set

这两个方法的功能:对受保护和私有属性访问的一个访问器,可以对从类外接收到的数据进行安全性和合理性的校验。

__set方法接收两个参数,第一个是属性名称,第二个是要赋的新值。

__get方法接收一个参数,属性名称。


1. public属性能提供在类外修改属性的服务,因此,对于public属性,不会走__get和__set流程。

class D{    public $name = 'D name';    protected $gender = 'male';    private $age = 18;    public function __set($name, $value){        echo '__set
'; //if(in_array($name, ['name', 'gender', 'age'])) $this->$name = $value; } public function __get($name){ echo '__get
'; //if(!in_array($name, ['name', 'gender', 'age'])) return NULL; return $this->$name; }};


运行结果:
new D name //name为public属性,不会走get和set__set__getnew D gender__set__getnew D age

2. 我们也可以加入数据校验的功能,打开注释就可以进行校验。

3.两个方法必须是public访问,否则会提示错误,我们可以从这两个函数的功能来出发思考,就不难想象为什么需要public访问控制。


六.继承

终于到了可以让你的菊花开苞的特性,没有继承,所有类都是渣渣,因为有了继承,所以...问题就特么的一大波一大波的来啦...让我们来深入浅出一下此继承特性。

什么继承就不说了吧,文章的开头就有一个继承的小示例。

有了继承会出现什么问题呢?想一下,如果B继承了A...真的是难以想象...

1. 构造函数,这个放心,跟继承没有太多关系,相当于两个类里的构造函数,但是怎么也有个父子关系啊,不能把事做的太绝,所以,上面讲过,如果有需要,可以手动调用父类的构造函数,可以看下上面的示例。

2.单方向继承,继承是单方向的,子类可以从父类继承,但父类却不能从子类继承特性,示例:

class A{	public $attr1;	public function oper1(){	}};class B extends A{	public $attr2;	public function oper2(){	}};//子类可以继承父类$b = new B;$b->oper1();$b->attr1 = 'attr1 value';$b->oper2();$b->attr2 = 'attr2 value';//父类不能继承子类$a = new A;$a->oper2();//出错$a->attr1();//出错

3. 重载,一提到php的重载就特别别扭,因为他的重载放到其他语言里叫做重写overwrite,我还是习惯将这个特性说为重写,大家随便。

public重载:

class E{    public $attr1 = 'E attr1 value';    public function oper1(){        echo 'E oper1
'; echo 'attr1 value = ', $this->attr1, '
'; }};class F extends E{ public $attr1 = 'F attr1 value'; public function oper1(){ //parent::oper1(); echo 'F oper1
'; echo 'attr1 value = ', $this->attr1, '
'; }};$f = new F;$f->oper1();

运行结果:

F oper1
attr1 value = F attr1 value


F继承了E并且重写了E的attr1和oper1,因此,在调用oper1时,$this->attr1显示F attr1 value,如果打开注释parent::oper1调用父类的Oper1方法,运行结果如下:

E oper1
attr1 value = F attr1 value //attr1属性已经被子类重写的attr1属性覆盖
F oper1
attr1 value = F attr1 value

可以看出子类重写父类的属性和方法后,会覆盖父类相应的属性和方法。


private重载

class E{    private $attr1 = 'E attr1 value';    public function oper1(){        echo 'E oper1
'; echo 'attr1 value = ', $this->attr1, '
'; }};class F extends E{ public $attr1 = 'F attr1 value'; public function oper1(){ parent::oper1(); echo 'F oper1
'; echo 'attr1 value = ', $this->attr1, '
'; }};$f = new F;$f->oper1();
以上代码只变动了一处地方,就是把父类$attr1的访问属性变成private,那重载机制如何执行呢?先看运行结果:

E oper1
attr1 value = E attr1 value //父类私有的属性
F oper1
attr1 value = F attr1 value


之前我们说过,private属性和方法子类是继承不了的,这种情况,遵循一个原则:

private属性在那个类里调用的,就显示哪个类里的属性值。

示例中的parent::oper1方法调用的是E类的oper1方法,在E的oper1方法内又调用了$this->attr1,attr1是private并没有被子类继承,因此,调用的就是类E里的attr1属性值。


protected重载与public重载一致


类属性的继承

class G{    public static $attr1 = 'G attr1 value';    public function oper1(){        echo 'G oper1
'; echo 'attr1 value = ', self::$attr1, '
'; }};class H extends G{ public static $attr1 = 'H attr1 value'; public function oper1(){ parent::oper1(); echo 'H oper1
'; echo 'attr1 value = ', self::$attr1, '
'; }};$h = new H;$h->oper1();

运行结果:

G oper1
attr1 value = G attr1 value
H oper1
attr1 value = H attr1 value

其实不管G类的attr1属性是public还是private,结果都一样。

个人是这么理解的,类属性可以继承,但谈不上重载,那关于子类调用父类的属性也有一规则:

self或者parent只代表本类,因此,根据这一原则可以断定,属性的值一定是本类属性的值,与子类无关。(特殊情况时php的静态延迟加载机制)。


七.静态延迟加载

既然已经提到了静态延迟加载,就趁热打铁讲一下,H和G的例子大家已经看了,那我就是想要在子类中调用父类的东东怎么办?静态延迟加载就是解决这个问题,请看两个示例:

示例1:

还是H和G类的例子

class G{    public static $attr1 = 'G attr1 value';    public function oper1(){        echo 'G oper1
'; echo 'attr1 value = ', static::$attr1, '
'; }};class H extends G{ public static $attr1 = 'H attr1 value'; public function oper1(){ parent::oper1(); echo 'H oper1
'; echo 'attr1 value = ', self::$attr1, '
'; }};$h = new H;$h->oper1();
运行结果:

G oper1
attr1 value = H attr1 value
H oper1
attr1 value = H attr1 value

上面代码只是将G类里的self::$attr1改写成了static::$attr1,运行结果就不一样了


示例2:

class I {    public static function who(){        echo __CLASS__, '
'; } public static function test(){ static::who(); }};class J extends I{ public static function who(){ echo __CLASS__,'
'; }};

运行结果:

J


通过这两个例子,可以好好的领悟一下static的静态延迟绑定。


写的有点多,主要是因为一牵扯继承就停不下来....面向对象还有一些只是点,后面有时间再补上吧...谢谢,如若有错误的地方,敬请大家指出,随时更正,谢谢!!

上一篇:

下一篇: