第6课:面向对象:类

传说中高大上的类
类主要实现对代码的封装,让自己的代码更有层次,结构更清晰,井井有条
目的是提高扩展性与通用性,便于维护
一般常用的是抽象类与继承
抽象类一般写一些通用的方法,不一定非要是某个事物的抽象,接口类一般是确定类中方法清单,确定类功能,继承是实现同一功能的各种定制版本

1.类的结构和调用
class className{}
调用:
$obj = new className();
当类有含参数构造函数,还应传入参数
$obj = new className($v, $v2…);

2.继承
class Son {}继承class Root {}写法
class Son extends Root{};
在子类里可以重载父类的方法,参数个数要保持一致,否则会报错

Final 关键字
PHP 5新增的一个关键字,如果父类中的方法被声明为 final,则子类无法覆盖该方法。同样如果一个类被声明为 final,则不能被继承。
需要注意的是: 属性不能被定义为 final,只有类和方法才能被定义为 final。

范围解析操作符(::)
范围解析操作符或者更简单地说是一对冒号,可以用于访问静态成员,类常量,还可以用于覆盖类中的属性和方法。
self,parent 和 static 这三个特殊的关键字是用于在类定义的内部对其属性或方法进行访问的

比如我们都有一个上传图片的操作,但是某一类特殊图片可能要加权限,这个时候就可以继承上传图片的基类,在里面加其他操作
通过继承,很方便的实现程序的扩展。

下面以一个dog类来说明继承的作用,dog类是一个基础类,来说明狗的基本特征,但是每家每户的狗也有自己的特点,继承自dog但是又和dog有差别
<?php
//猫有两只眼睛,会喵喵叫,会跑.
class Cat {
	protected  $eyeNumber =2; //属性
	//返回封装属性的方法.
	public function getEyeNumber(){ 
		return $this->eyeNumber;
	}
	//猫会叫	
	public function yaff(){
		return  "Cat miao..";
	}
	//猫会跑
	public function run(){
		return  "Cat run..";
	}
}
$cat = new Cat();
echo "Cat have " . $cat->getEyeNumber()." eyes. <br>";
echo $cat->yaff() . "<br>" . $cat->run();

//这是我的小猫叫"godeye",它很小.不会喵喵叫,只会哼哼哼..
class MyCat extends Cat {
	private $name = "godeye";
	public function getName(){
		return $this->name;
	}
        public function yaff(){
		return  $this->name . " yaff, heng...heng ..";
	}	
}
$myCat = new MyCat();
echo $myCat->getName() . " have " . $myCat->getEyeNumber() . " eyes. <br>";
echo $myCat->yaff() . "<br>" . $myCat->run();
?>


3.抽象类
一些公用的方法可以抽象出来,放在抽象类里,方便其他类的调用
abstract class Test { }
在使用的时候抽象类一般都是当做父类,其他功能实现类继承抽象类
然后在功能类方法体中用self::方法名来调用抽象类中的公共方法

4.方法重载
由于PHP是弱类型语言,因此函数的输入参数类型无法确定,并且对于一个函数,比如只定义了3个输入参数,PHP却运行调用的时候输入4个或者更多的参数。因此基于这2点,注定了PHP中无法重载函数
但是有3种办法可以实现伪重载
第一种:方法不写参数,也就没有参数的问题了
在方法体中用func_get_args()返回包含所有参数的数组然后再用call_user_func_array调用

func_num_args() 返回传递给该函数参数的个数
func_get_arg($arg_num) 取得指定位置的参数值,$arg_num位置index从0开始n-1。
func_get_args() 返回包含所有参数的数组

第二种:用__call魔术方法来实现
举例
<?php
class A
{
     function __call ($name, $args )
    {
        if($name=='f')
        {
            $i=count($args);
            if (method_exists($this,$f='f'.$i)) {
                call_user_func_array(array($this,$f),$args);
            }
        }
    }
    function f1($a1)
    {
        echo "1个参数".$a1."<br/>";
    }
    function f2($a1,$a2)
    {
        echo "2个参数".$a1.",".$a2."<br/>";
    }
    function f3($a1,$a2,$a3)
    {
          echo "3个参数".$a1.",".$a2.",".$a3."<br/>";
    }
}
(new A)->f('a');
(new A)->f('a','b');
(new A)->f('a','b','c');
?>

第三种:增加无用的参数,保证重载的方法与原方法参数一致

5.类的单例模式
在一个API请求中,可能多次实例化同一个类,调用类里面不同的方法
每次new操作都是有开销的,如果能保证一个类在一次请求中只实例化一次?
以封装的mysql基类为例
<?php
class Mysql {

    private static $handle;

    public function __construct($db = 'master') {
	//操作
    }

    public function __destruct() {
        $this->conn = null;
    }

    public static function getInstance($db = 'master') {
	if (!isset(self::$handle[$db]) || !is_object(self::$handle[$db])) {
		self::$handle[$db] = new self($db);
	}
	return self::$handle[$db];
    }
}
?>
其中的getInstance就是来实现单例模式
利用一个静态变量$handle来记录实例化的结果,因为$handle的生存周期是整个调用过程,所以能保证类在一次调用中只实例化一次
使用方式:
$mysql = Mysql::getInstance();

判断类存在不存在会用到class_exists,用法
if (class_exists('MyClass')) {
    $myclass = new MyClass();
}
我们判断一个类的方法存在不存在经常会用到
method_exists()
当然还有一个callable()
ethod_exists()与is_callable()的区别在于在php5中,一个方法存在并不意味着它就可以被调用。对于 private,protected和public类型的方法,method_exits()会返回true,但是is_callable()会检查存在其是否可以访问,如果是private,protected类型的,它会返回false

get_class 返回对象的类名
$bar = new Godeye();
echo "Its name is " , get_class($bar) , "\n";
当然,get_class也可以用于类具体的方法中get_class($this)

打赏  如对你有帮助,请我喝杯咖啡吧!