• 面向对象思想的核心概念


    PHP的魔术方法

    __construct方法:PHP中没有构造方法的重载

    __destruct方法:析构方法允许在销毁一个对象之前执行一些特定操作,例如关闭文件、释放结果集等

    当堆内存段中的对象失去访问它的引用时,就不能被访问了,也就成为垃圾对象了。通常对象的引用被赋予其他的值或者是在页面运行结束时,对象都会失去引用

    访问属性:使用下面的方法之后,访问不存在的属性时不会报错

    __set方法:void __set(string name, mixed value)  第一个参数需要传入在为私有属性设置值时的属性名,第二个参数则需要传入为属性设置的值。这个方法不需要主动调用,可以在方法前面也加上private修饰,防止用户直接调用。这个方法是在用户值为私有属性设置值时自动调用的

    __get方法:这两个方法是用来完成对所有私有属性都能获取和赋值的操作

    __isset方法:用来检查私有属性是否存在的方法

    __unset方法:用来删除对象中私有属性的方法

    <?php
    class Account {
        private $user = 1;
        private $pwd = 2;
    
        public function __set($name, $value) {
            echo "Setting $name to $value 
    ";
            echo "<br>";
            $this -> $name = $value;
        }
    
        public function __get($name) {
            if (!isset($this->$name)) {
                echo "未设置";
                echo "<br>";
                $this -> $name = "正在设置默认值";
            }
            return $this->$name;
        }
    }
    
    $a = new Account();
    echo $a -> user;
    echo "<br>";
    $a -> name = 5;
    echo $a -> name;
    echo "<br>";
    echo $a -> big;
    
    ?>
    
    //1
    Setting name to 5 
    5
    未设置
    Setting big to 正在设置默认值 
    正在设置默认值

    访问方法:使用下面的方法之后,访问不存在的方法不会报错

    __call方法

    mixed __call(string $name, array $arguments)
    //当调用一个不可访问的方法(未定义,或者不可见)时,__call()会被调用。其中$name参数是要调用的方法名称
    //$arguments参数是一个数组,包含着要传递给方法的参数
    
    //使方法的动态创建成为可能,在MVC等框架设计中是很有用的语法。假设一个控制器调用了不存在的方法,那么只要定义了__call魔术方法,就能友好地处理这种情况
    <?php
    class TestClass {
        function printHello(){
            echo "Hello<br>";
        }
    
        function __call($functionName, $args)
        {
            // TODO: Implement __call() method.
            echo "你所调用的函数: ".$functionName."(参数: ";
            print_r($args);
            echo ")不存在<br>
    ";
        }
    }
    
    $obj = new TestClass();
    $obj->myFun("one", 2, "three");
    $obj->otherFun(8, 9);
    $obj->printHello();
    ?>

    __callStatic方法

    __toString方法:是在直接输出对象引用时自动调用的方法

    如果类定义了__toString方法,就能在测试时,echo打印对象体,对象就会自动调用它所属类定义的__toString方法,格式化输出这个对象所包含的数据

    仍然可以用print_r和var_dump函数输出一个对象

    直接echo一个对象就会报语法错误,而如果这个对象实现__toString方法后就可以直接输出==>echo本来可以打印一个对象,而且也实现了这个接口,但是PHP对其做了个限制,只有实现__toString后才允许使用

    <?php
    //声明一个测试类,在类中声明一个成员属性和一个__toString()方法
    
    class TestClass {
        private $foo;
    
        function __construct($foo)
        {
            $this->foo = $foo;
        }
    
        public function __toString()
        {
            // TODO: Implement __toString() method.
            return $this->foo;
        }
    }
    
    $obj = new TestClass('Hello');
    echo $obj;
    ?>

    对象串行化

    串行化  serialize()函数  参数为对象的引用名,返回值为一个对象被串行化后的字符串

    反串行化  unserialize()函数  把对象串行化后转换的二进制字符串再转换为对象  参数为serialize()函数的返回值,返回值是重新组织好的对象

    类的组合与继承

    组合是指在一个类中创建另一个类的对象,并把后者作为前者的一个属性,并调用它的方法处理问题,这种复用方式叫“组合”

    ::操作符用于调用父类的方法,还用来作为类常量和静态方法的调用

    低耦合指模块与模块之间,尽可能地使模块间独立存在;模块与模块之间的接口尽量少而简单

    继承:

    子类重写父类的方法:可以使用parent::方法名来获取父类的代码

    常见关键字:

    final

    static  类名::静态属性名  类名::静态成员方法名

    在类中声明的成员方法中,也可以使用self来访问其他静态成员,因为静态成员是属于类的,所以不能通过$this访问

    self::静态成员属性名

    self::静态成员方法名

    如果在类的外部访问静态成员,可以使用类名或者对象名来引用

    单态设计模式

    <?php
    /**
    声明一个类Db,用于演示单态模式的使用
     */
    class DB {
        //声明一个私有的、静态的成员属性$obj
        private static $obj = null;  
        
        //构造方法,使用private封装后则只能在类的内部使用new去创建对象
        private function __construct()
        {
            //完成数据库连接操作
            echo "连接数据库成功<br>";
        }
        
        //只有通过这个方法才能返回本类的对象
        static function getInstance(){
            if(is_null(self::$obj)) {
                self::$obj = new self();
            }
            return self::$obj;
        }
        
        //执行SQL语句完成对数据库的操作
        function query($sql) {
            echo $sql;
        }
    }
    
    $db = DB::getInstance();
    $db->query("select * from user");
    ?>

    const关键字:

    在PHP中定义常量是通过调用define()函数来完成的,但要将类中的成员属性定义为常量,则只能使用const关键字。将类中的成员属性使用const关键字标识为常量,其访问的方式和静态成员一样,都是通过类名或者在成员方法中使用self关键字访问,也不能用对象来访问

    使用const声明的常量名称前不使用$

    instanceof关键字

    克隆对象:克隆以后,原本和副本两个对象完全独立、互不干扰

    <?php
    class Person {
        private $name;
        private $sex;
        private $age;
        
        function __construct($name = "", $sex = "",$age=1)
        {
            $this->name = $name;
            $this->sex = $sex;
            $this->age = $age;
        }
        
        function say(){
            echo "我的名字: ".$this->name.", 性别: ".$this->sex.", 年龄: ".$this->age."<br>";
        }
    }
    
    $p1 = new Person("张三", "男", 20);
    $p2 = clone $p1;
    $p1 -> say();
    $p2 -> say();
    ?>
    
    <?php
    //如果需要对克隆后的副本对象在克隆时重新为成员属性赋初值,则可以在类中声明一个魔术方法“__clone()”
    class Person2 {
        private $name;
        private $sex;
        private $age;
    
        function __construct($name = "", $sex = "",$age=1)
        {
            $this->name = $name;
            $this->sex = $sex;
            $this->age = $age;
        }
        
        //声明此方法则在对象克隆时自动调用,用来为新对象重新赋值
        function __clone(){
            $this->name = "我是". $this->name. "的副本";
            $this->age = 10;
        }
    
        function say(){
            echo "我的名字: ".$this->name.", 性别: ".$this->sex.", 年龄: ".$this->age."<br>";
        }
    }
    
    $p1 = new Person("张三", "男", 20);
    $p2 = clone $p1;
    $p1 -> say();
    $p2 -> say();
    ?>

    抽象类与接口

    abstract function fun1();
    abstract function fun2();
    
    //只要在声明类时有一个方法是抽象方法,那么这个类就是抽象类,抽象类也要使用abstract关键字修饰。在抽象类中可以有不是抽象的成员方法和成员属性,但访问权限不能使用private关键字修饰为私有的
    抽象类中可以定义非抽象方法
    
    //接口中不能声明非抽象方法,不能在接口中声明变量,只能使用const关键字声明为常量的成员属性,而且接口中的所有成员都必须有public的访问权限

    匿名类

    <?php
    $person = new class {
        function say() {
            echo "匿名类!";
        }
    };
    
    $person->say();
    ?>
    
    <?php
    $person1 = new class ('哈哈'){
        public $name;
        function  __construct($name) {
            $this->name = $name;
        }
    
        function say() {
            echo "匿名类: {$this->name}";
        }
    };
    $person1->say();
    ?>
    
    //匿名类! 匿名类: 哈哈
    <?php
    class SomeClass {}  //声明一个类SomeClass作为父类
    interface SomeInterface {}  //声明一个接口SomeInterface用匿名类实现
    trait SomeTrait {}  //声明一个trait,导入到匿名类中
    
    
    //使用var_dump()直接输出匿名类的对象
    //声明一个匿名类,通过构造函数为成员属性$num赋初值
    //声明匿名类时继承SomeClass类
    //声明匿名类时实现接口SomeInterface
    var_dump(new class(100) extends SomeClass implements SomeInterface {
        private $num;
        public function __construct($num)
        {
            $this->num = $num;
        }
        use SomeTrait;
    });
    
    
    ?>
    
    <?php
    //匿名类还可以在一个类的内部方法中声明,当匿名类被嵌套进普通类后,不能访问这个外部类的
    //private、protected方法或者属性。为了访问外部类protected属性或方法,匿名类可以继承此外部类
    //为了使用外部类的private属性,必须经过构造器传进来
    
    class Outer {
        private $prop = 1;
        protected $prop2 = 2;
    
        protected function func1(){
            return 3;
        }
    
        //声明一个外部类的成员方法,在方法返回内部匿名类对象
        public function func2(){
            //声明和返回匿名类对象
            //通过构造方法将外部类的私有成员,访问外部类的私有属性
            //通过继承外部类,访问外部类的私有成员
            return new class($this->prop) extends Outer {
                private $prop3;  //内部类的私有成员
    
                public function __construct($prop)
                {
                    $this->prop3 = $prop;
                }
    
                public function func3() {
                    return $this->prop2 + $this->prop3 + $this->func1();
                }
            };
        }
    }
    
    //访问内部匿名类实例中的func3()
    echo (new Outer) -> func2() ->func3();
    ?>

    多态:同一类的对象收到相同消息时,会得到不同的结果,而这个消息是不可预测的。多态,就是多种状态,多种结果

    多态是一种通过多种状态或阶段描述相同对象的编程方式。它的真正意义在于:实际开发中,只要关心一个接口或基类的编程,而不必关心一个对象所属于的具体类

    //通过判断对象的类属性实现多态
    <?php class employee { protected function working() { echo '本方法需重载才能运行'; } } class teacher extends employee { public function working() { echo '教书'; } } class coder extends employee { public function working() { echo '敲代码'; echo "<br>"; } } function dprint($obj) { if (get_class($obj) == 'employee') { echo 'Error'; } else { $obj->working(); } } dprint(new teacher()); dprint(new coder()); dprint(new employee());
    //通过接口实现多态
    
    <?php
    interface employee {
        public function working();
    }
    
    class teacher implements employee {
        public function working() {
            echo '教书';
        }
    }
    
    class coder implements employee {
        public function working()
        {
            echo '敲代码';
        }
    }
    
    function dprint(employee $i) {
        $i -> working();
    }
    
    $a = new teacher;
    $b = new coder();
    dprint($a);
    dprint($b);

    PHP中父类和子类存在继承关系,但不存在血缘关系,子类无法向上转型为父类。

    面向接口编程

    接口本身什么也不做,系统在内部实现了接口的行为,所以只要实现了这个接口,就可以使用接口提供的方法,这就是接口“即插即用”思想

    //Traits和接口很像,不同的是Traits可以导入包含代码的接口,Traits和接口都是对“多重继承”的一种变相实现
    <?php
    trait Hello {
        public function sayHello() {
            echo 'Hello';
        }
    }
    
    trait World {
        public function sayWorld() {
            echo 'World';
        }
    }
    
    class MyHelloWorld {
        use Hello, World;
        public function sayExclamationMark() {
            echo '!';
        }
    }
    
    $o = new MyHelloWorld();
    $o -> sayHello();
    $o -> sayWorld();
    $o -> sayExclamationMark();
    ?>
    <?php
    trait DemoTrait {
        public $property1 = true;
        static $property2 = 1;
        function method1() {
            //codes
        }
        abstract public function method2();
    }
    
    /**
    trait的基本使用:Trait不能通过它自身来实例化对象,必须将其混入类中使用。相当于将Trait中的成员复制到类中,在应用类时就像使用自己的
     * 成员一样
     */
    trait Demo1_trait {
        function method1() {
    
        }
    
        function method2() {
            
        }
    }
    
    class Demo1_class {
        use Demo1_trait;
    }
    
    $obj = new Demo1_class();
    
    $obj->method1();
    $obj->method2();
    
    ?>
    <?php
    
    trait Demo1_trait {
        function func() {
            echo "第一个Trait中的func方法";
        }
    }
    
    trait Demo2_trait {
        function func() {  //两个同名方法有冲突
            echo "第二个Trait中的func方法";  
        }
    }
    
    class Demo_class {
        use Demo1_trait, Demo2_trait {
            Demo1_trait::func insteadof Demo2_trait;  //Demo2_trait中声明的在这里声明使用Demo1_trait的func替换
        }
    }
    
    $obj = new Demo_class();
    
    $obj->func();
    
    ?>

    为了对使用的类施加强制要求,Trait支持抽象方法的使用。如果在Trait中声明需要实现的抽象方法,这样就使得使用它的类必须先实现它

    注意:

    • Trait会覆盖调用类继承的父类方法
    • 从基类继承的成员被Trait插入的新成员所覆盖。来自当前类的成员覆盖了Trait的方法,而Trait则覆盖了被继承的方法
    • Trait不能像类一样使用new实例化对象
    • 单个Trait可由多个Trait组成
    • 在单个类中,用use引入Trait,可以引入多个
    • Trait支持修饰词,例如final、static、abstract
    • 可以使用insteadof及as操作符解决Trait之间的冲突
    • 使用as语法还可以用来调整方法的访问控制

    反射

    面向对象编程中对象被赋予了自省的能力,而这个自省的过程就是反射

    动态获取信息以及动态调用对象方法的功能称为反射API

    <?php
    class person {
        public $name;
        public $gender;
        public function say() {
            echo $this->name, "	is", $this->gender, "
    ";
        }
        public function __set($name, $value) {
            echo "Setting $name to $value 
    ";
            $this -> $name = $value;
        }
        public function __get($name) {
            if (!isset($this -> $name)) {
                echo '未设置';
                $this -> $name="正在设置默认值";
            }
            return $this -> $name;
        }
    }
    
    $student = new person();
    echo $student -> name;
    $student -> name = "tom";
    $student -> gender = "male";
    $student -> age = 24;
    $student -> say();
    echo $student -> name;
    print "<br>";
    
    //获取对象属性列表
    $reflect = new ReflectionObject($student);
    $props = $reflect->getProperties();
    foreach ($props as $prop) {
        print $prop -> getName()."
    ";
        print "<br>";
    //    print "<br>";
    }
    print "<br>";
    
    //获取对象方法列表
    $m = $reflect->getMethods();
    foreach ($m as $prop) {
        print $prop->getName()."
    ";
        print "<br>";
    
    }
    
    //也可以使用class函数,返回对象属性的关联数组以及更多的信息
    //返回对象属性的关联数组
    var_dump(get_object_vars($student));
    //类属性
    var_dump(get_class_vars(get_class($student)));
    //返回由类的方法名组成的数组
    var_dump(get_class_methods(get_class($student)));
    
    //获取对象属性列表所属的类
    echo get_class($student);
    
    ------------------------------
    Setting age to 24 tom ismale tom
    name 
    gender 
    age 
    
    say 
    __set 
    __get 
    array(3) { ["name"]=> string(3) "tom" ["gender"]=> string(4) "male" ["age"]=> int(24) } array(2) { ["name"]=> NULL ["gender"]=> NULL } array(3) { [0]=> string(3) "say" [1]=> string(5) "__set" [2]=> string(5) "__get" } person
    //反射获取类的原型
    $obj = new ReflectionClass('person');
    $className = $obj -> getName();
    $Methods = $Properties = array();
    foreach ($obj -> getProperties() as $v)
    {
        $Properties[$v->getName()] = $v;
    }
    foreach($obj->getMethods() as $v){
        $Methods[$v->getName()] = $v;
    }
    
    echo "class {$className}<br>{<br>";
    is_array($Properties)&&ksort($Properties);
    
    foreach($Properties as $k => $v) {
        echo "	";
        echo $v -> isPublic()? 'public' : '', $v -> isPublic()? 'private':'', $v -> isProtected()? 'protected':'',
        $v->isStatic()? 'static' :' ';
        echo "{$k}<br>";
    }
    
    echo "
    ";
    if(is_array($Methods)) ksort($Methods);
    foreach($Methods as $k => $v) {
        echo "function{$k}(){}<br>";
    }
    
    echo "}<br>";

    异常和错误处理

    <?php
    class emailException extends exception {
    
    }
    
    class pwdException extends exception {
        function __toString()
        {
            return "<div class = "error">Exception{$this->getCode()}:
            {$this->getMessage()}
            in File:{$this->getFile()} on line:{$this->getLine()} </div>";
            //改写抛出异常结果
        }
    }
    
    
    //异常分发
    function reg($reginfo=null){
        if (empty($reginfo) || isSet($reginfo)) {
            throw new Exception("参数非法");
        }
        if (empty($reginfo['email'])){
            throw new emailException("邮件为空");
        }
        if ($reginfo['pwd'] != $reginfo['repwd']) {
            throw new pwdException("两次密码不一致");
        }
        echo "注册成功";
    }
    
    //对异常进行分拣并做处理
    try {
        reg(array('email'=>'waitfox@qq.com', 'pwd'=>123456, 'repwd'=>12345678));
    } catch(emailException $ee) {
        echo $ee -> getMessage();
    } catch(pwdException $ep) {
        echo $ep;
        echo PHP_EOL, '特殊处理';
    } catch(Exception $e) {
        echo $e->getTraceAsString();
        echo PHP_EOL, '其他情况,统一处理';
    }
    <?php
        try{
            //可能出错的代码段
            if (文件上传不成功) throw(上传异常);
            if (插入数据库不成功) throw(数据库操作异常);
        } catch(异常){
            必须的补救措施,如删除文件、删除数据库插入记录
        }
    ?>
    
    
    
    <?php
        上传{
            if(文件上传不成功) throw(上传异常);
            if(插入数据库不成功) throw(数据库操作异常);
        }
    
        //其他代码...
        try{
            上传;
            其他;
        } catch(上传异常) {
            必须的补救措施,如删除文件,删除数据库插入记录
        } catch(其他异常){
            记录log
        }
    ?>

    错误处理机制

    PHP里有一套错误处理机制,可以使用set_error_handler接管PHP错误处理,也可以使用trigger_error函数主动抛出一个错误

    set_error_handler函数设置用户自定义的错误处理函数,函数用于创建运行期间的用户自己的错误处理方法。它需要先创建一个错误处理函数,然后设置错误级别

    PHP程序的错误发生一般归属于:语法错误、运行时错误、逻辑错误

    trigger_error()函数和die()函数

    //set_error_handler()函数设置用户自定义的错误处理函数。函数用于创建运行期间的用户自己的错误处理方法。它需要先创建一个错误处理函数,然后设置错误级别
    set_error_handler(error_function, error_types)
    error_function:规定发生错误时运行的函数
    error_types:规定在哪个错误报告级别会显示用户定义的错误,默认为“E_ALL

    命名空间

    解决重名问题。命名空间将代码划分出不同的区域,每个区域的常量、函数和类的名字互不影响

    在命名空间里,define的作用是全局的,const则作用于当前空间

    //独立的命名空间使用namespace关键字声明
    <?php
    namespace MyProject;
    
    
    ?>
    
    //namespace需要写在PHP脚本的顶部,必须是第一个PHP指令(declare除外)
    
    <?php
    namespace MyProject1;
    
    const TEST = 'this is a const';
    
    function demo(){
        echo "this is a function";
    }
    
    class User {
        function fun() {
            echo "this is User's fun()";
        }
    }
    
    echo TEST;
    demo();
    
    namespace MyProject2;
    
    const TEST2 = "this is MyProject2 const";
    echo TEST2;
    
    //调用MyProject1空间中的demo函数
    MyProject1demo();
    
    //使用MyProject1空间中的类实例化对象
    $user = new MyProject1User();
    $user->fun();
    
    ?>

    命名空间的子空间和公共空间

  • 相关阅读:
    Python 面向对象
    python Flask
    工作中的Python脚本
    python模块
    python函数
    Python小课题练习作业
    Python文件处理
    Maven 生成可执行的jar包
    Maven [ERROR] 不再支持源选项 5。请使用 6 或更高版本
    MySQL 导入导出数据
  • 原文地址:https://www.cnblogs.com/liushoudong/p/13166512.html
Copyright © 2020-2023  润新知