3

PHP 使用了一段时间, 从对OOP的不了解, 再到使用, 觉得挺好, 特写下

看面向对象, 我是看的这个鸡啄米的c++, http://www.jizhuomi.com/softw...

OOP并不是为了面向对象而面向对象, 而是为了达到代码的重用性灵活性扩展性

对象和类

从先有对象才有人类, 这个来说, 有点不合理的合理

类:具有相同属性的一组对象的集合
对象:类实例化之后就是对象
看下一般的类的定义

<?php
class Person{
    // 成员变量
    private $name;
    private $sex;
    private $age;
    // 构造函数
    function __construct($name="",$sex="",$age=""){
        if($name===""||$sex===""||$age===""){
            throw new Exception("must set name , sex, age");
        }
        $this->name = $name;
        $this->age  = $age;
        $this->sex  = $sex;
    }
    // 析构函数
    function __destruct(){
        echo "byebye\n";
    }
    // 成员方法
    function eat(){
        echo "my name is ". $this->name;
    }
    function sleep(){
        echo "i am sleeping";
    }
}
// 类的实例化
$jaime = new Person("jaime", "man", 24);
$jaime->eat();

?>

保存为index.php, 在命令窗口输入

$ php index.php
my name is jaime
byebye

如果

$jaime = new Person("jaime", "man", 24);

改为

$jaime = new Person("jaime", "man");

则会触发异常, 会有以下的消息出来, 包括错误信息, 错误行数, 和堆栈信息

$ php index.php

Fatal error: Uncaught exception 'Exception' with message 'must set name , sex, age' in E:\net\index.php on line 15

Exception: must set name , sex, age in E:\net\index.php on line 15

Call Stack:
    0.0025     242440   1. {main}() E:\net\index.php:0
    0.0025     243016   2. Person->__construct() E:\net\index.php:30

对象和内存

说点理论上的东西吧,

内存的分类:

堆(heap): 不可直接存取, 存储占有空间很大的数据类型的数据

栈(stack): 可以直接存取, 存储占用相同空间长度并且占用空间小的数据, 如存放局部变量,函数参数,当前状态,函数调用信息等

$jaime = new Person("jaime", "man", 24);

$jaime是存放在栈内存里面的引用变量, 即存储在堆中对象的首地址, 一个指针

new Person 实例化出来的对象是存放在堆内存里面的, 是真正的对象实例

对象和成员

变量,方法(内部成员函数)的前缀:

private: 私有成员

public:  公有成员(外部接口),没有加修饰, 默认就是public

protected: 保护型成员, 继承的类可以调用

访问private修饰的变量

Fatal error: Cannot access private property Person::$name in E:\net\index.php on line 36

如果想访问private, protected修饰的成员:

  1. 把private改为public

  2. 使用__get(), ___set()魔术方法, 但是还是写出代码来看看根据实际情况使用

<?php
class Person{
    private $name;
    private $sex;
    private $age;
    function __construct($name="",$sex="",$age=""){
        if($name===""||$sex===""||$age===""){
            throw new Exception("must set name , sex, age");
        }
        $this->name = $name;
        $this->age  = $age;
        $this->sex  = $sex;
    }
    function __destruct(){
        echo "byebye\n";
    }

    function eat(){
        echo "my name is ". $this->name."\n";
    }
    function sleep(){
        echo "i am sleeping\n";
    }

    function __get($property_name){
        $access_array = ['age','name'];// 只允许访问age,name两个私有成员
        if(in_array($property_name, $access_array)){
            return ($this->$property_name);
        }
        else{
            return NULL;
        }
    }
    function __set($property_name, $value){
        $access_array = ['age'];// 只允许访问age这个私有成员
        if(in_array($property_name, $access_array)){
            $this->$property_name = $value;
        }
    }

}

$jaime = new Person("jaime", "man", 24);
$jaime->eat();
echo ($jaime->age === NULL)? "NULL":$jaime->age;
echo "\n";
echo ($jaime->sex === NULL)? "NULL":$jaime->sex;
$jaime->age = 80;
echo "\n";
echo ($jaime->age === NULL)? "NULL":$jaime->age;
echo "\n";
$jaime->name = "lll";
echo ($jaime->name === NULL)? "NULL":$jaime->name;
echo "\n";
?>

执行结果如下

$ php index.php
my name is jaime
24
NULL
80
jaime
byebye

类的继承

<?php
class Person{
    private $name;
    private $sex;
    private $age;
    function __construct($name="",$sex="",$age=""){
        if($name===""||$sex===""||$age===""){
            throw new Exception("must set name , sex, age");
        }
        $this->name = $name;
        $this->age  = $age;
        $this->sex  = $sex;
    }
    function __destruct(){
        echo "byebye\n";
    }

    function hello(){
        echo "my name is ". $this->name."\n";
    }
    function sleep(){
        echo "i am sleeping\n";
    }
}


class Student extends Person
{
    private $school;

    function __construct($name, $sex, $age, $school)
    {
        // 调用父类方法, 构造函数
        parent::__construct($name, $sex, $age);
        $this->school = $school;
    }
    // 重载了父类方法
    function sleep(){
        echo "afternoon sleep\n";
        // 调用父类方法
        parent::sleep();
    }
}

$jaime = new Student("jaime", "man", 24,"zh");
$jaime->hello();
$jaime->sleep();
?>

执行后输出

$ php index.php
my name is jaime
afternoon sleep
i am sleeping

byebye

调用父类的方法需要用parent

静态成员和常量

no bb, show code

<?php
class Person
{
    // 静态成员属性
    public static $contry = "China";
    public static function say(){
        // 静态成员方法, 通过self访问其它静态成员
        // 类里面的静态方法只能访问类的静态的属性
        echo "I live in ".self::$contry."\n";
    }
    public function show(){
        echo "xxx".self::$contry."\n";
    }
}
// 输出静态属性
echo Person::$contry."\n";
// 调用静态方法, 外部调用用类名::静态方法
Person::say();
// 给静态属性重新赋值
Person::$contry = "American";
Person::say();
(new Person())->show();
?>

结果

$ php is.php
China
 en
I live in China
I live in American
xxxAmerican en

类的静态变量,类似于全局变量,能够被所有类的实例共享,类的静态方法也是一样的,类似于全局函数, 静态成员被这个类的每个实例对象所共享

访问静态方法访问静态成员不能用$this, 需要用self

$this表示了此方法的对象

'self'表示此静态方法所在的类, self::成员

抽象方法和抽象类

什么叫抽象?不具体的就叫抽象! so

抽象方法 : 类里面没有具体方法体的方法(其实就是不具体的方法)

抽象类: 含有抽象方法的类,

抽象类不能实例化会报错"Cannot instantiate abstract class <classname>", 有点像C里面的函数声明, 仅仅只是一个声明

<?php
abstract class AbstractClass{
    // 抽象类里面可以有不是抽象的成员
    public $variable;
    // 抽象方法
    abstract function fun1();
    abstract function fun2();

    function fun3{
        echo "我是抽象类中的非抽象方法";
    }
}
class demo0 extends AbstractClass{
    // 子类必须把父类中的抽象方法全部都实现, 否则子类中还存在抽象方法,仍是抽象类
    function fun1(){
        echo "call ".__FUNCTION__."\n";
    }
    function fun2(){
        echo "call ".__FUNCTION__."\n";
    }
}
// 我这里是想不出名字, 不建议这样做, 因为demo0实例化了3次
(new demo0())->fun1();
(new demo0())->fun2();
(new demo0())->fun3();
?>

接口interface

什么是接口?

如果一个内里面所有的方法都是抽象方法, 我们可以把声明方式换为接口

接口是一种特殊的抽象类, 接口不能包含成员的任何代码,只定义成员身。接口成员的具体代码由实现接口的类提供

<?php
interface One{
    // 定义常量
    const con = "xonst";
    // 定义抽象方法, 不用加abstract, 因为都是abstract
    function fun1();
    function fun2();
}
?>

接口的继承

<?php
interface Two extends One{
    function fun3();
    function fun4();
}
?>

接口的实现

<?php
interface One{
    // 定义常量
    const con = "xonst";
    // 定义抽象方法, 不用加abstract, 因为都是abstract
    function fun1();
    function fun2();
}

interface Two extends One{
    function fun3();
    function fun4();
}
// 使用“implements”这个关键字去实现接口中的抽象方法
class demo implements Two
{
    function fun1() {
        echo "call ".__FUNCTION__."\n";
    }
    function fun2() {
        echo "call ".__FUNCTION__."\n";
    }
    function fun3() {
        echo "call ".__FUNCTION__."\n";
    }
    function fun4() {
        echo "call ".__FUNCTION__."\n";
    }
}

(new demo())->fun1();
(new demo())->fun2();
(new demo())->fun3();
(new demo())->fun4();
?>

一个类实现多个接口

一个人要遵守的法律不止一步吧, 所以see code

<?php
interface One{
    // 定义常量
    const con = "xonst";
    // 定义抽象方法, 不用加abstract, 因为都是abstract
    function fun1();
    function fun2();
}

interface Two{
    function fun3();
    function fun4();
}
// 注意这里
class demo implements One, Two
{
    function fun1() {
        echo "call ".__FUNCTION__."\n";
    }
    function fun2() {
        echo "call ".__FUNCTION__."\n";
    }
    function fun3() {
        echo "call ".__FUNCTION__."\n";
    }
    function fun4() {
        echo "call ".__FUNCTION__."\n";
    }
}

(new demo())->fun1();
(new demo())->fun2();
(new demo())->fun3();
(new demo())->fun4();
?>

你娶了你老婆你得对她的家人负责吧, 就像下面

// 使用extends继承一个类,使用implements实现多个接口
class demo extend AbstractClass implements One, Two{
    ......
    // 所有接口中的方法都要实现才可以实例化对象
}

反射Reflection

需求: 导出或提取出关于类、方法、属性、参数等的详细信息, 甚至是判断某个方法是否存在
这里我不做多说, 看我在实际的项目中的实际应用,
这是一个API的入口处理函数, 如果存在这个方法就执行并返回结果, 不存在就抛出异常,
因为接口函数是不断增加甚至是变化的, 使用反射作为api的入口可以让你的具体的api函数变化了入口也不用改

try {
    // 使用工厂方法实例化具体的接口
    $instance = new \Api\Library\ApiFactory($module, $server, $this->params);
    // 反射方法
    $action   = new \ReflectionMethod($instance->instance, $method);
    // 判断方法的类型
    if (!$action->isPublic() || $action->isStatic()) throw new \ReflectionException();
    // 验证api参数
    $validator = new \Api\Library\ApiValidator();
    $result    = $validator->check($this->params);
    if (false === $result)  {
        $this->result['code'] = $validator->code ? : $this->result['code'];
        $this->result['msg']  = $validator->msg  ? : $this->result['msg'];
        throw new \Exception();
    }
} catch(\Exception $e){
    $this->_format();
}

参考:

  1. 《细说PHP 》 兄弟连

  2. PHP手册

  3. php面向对象(OOP)编程完全教程


优de良
333 声望13 粉丝

好好写代码