旗下导航:搜·么
当前位置:网站首页 > PHP教程 > 正文

PHP面向对象特征【php教程】

作者:搜搜PHP网发布时间:2019-11-26分类:PHP教程浏览:91


导读:面向对象的三个重要特征是封装、继续和多态。建立对象$对象名=new类名();$对象名=new类名;new是一个症结字,示意建立一个新的实例。...
面向对象的三个重要特征是封装、继续和多态。

建立对象

$对象名 = new 类名();
$对象名 = new 类名;
  • new 是一个症结字,示意建立一个新的实例。
  • 在类定义内部,可以用 new selfnew parent 建立新对象。

成员属性

成员属性必须要有接见润饰符,假如不写,会报错。

成员属性的默许值为NULL。

示例:

class Test {
    
    public $name; //共有
    protected $height; //庇护
    private $age; //私有
}

成员要领

成员要领假如不写接见润饰符,则默认为public。

我们可以指定成员要领里的参数的范例,如 类范例,或许数组范例(array),也可以是接口范例,然则接口范例要注重,因为接口没有实例,当我们声明参数范例为接口范例的时刻,那末传入的参数只如果完成了该接口的类的实例即可。

示例:

class Test {
    
    function hello() {} //默认为public
    public function say() {} //公有
    protected function smile() {} //庇护
    private function laugh() {} //私有
}

组织要领

  • 一个类里只能有一个组织要领
  • 没有返回值(纵然在组织要领里写了返回值也没有意义)
  • 在建立一个类的新对象时,体系会自动的挪用类的组织要领完成对新对象的初始化。
  • 假如我们没有重写默许组织函数,那末体系会默许帮我们建立一个没有参数的组织函数,public function __construct(){},假如我们重写了组织函数,那末我们自定义的组织函数就会掩盖体系默许的组织函数。
  • 假如我们自定义的组织函数里有行参,那末当我们建立对象的时刻就必需传入响应的实参。不然会报错。

示例:

class Test {

    public function __construct() {
        echo 'hello, world<br>';
    }
}

$testObj = new Test();


class One {

    public function __construct($param) {

        echo $param;
    }
}

$oneObj = new One('hello, world<br>');

输出效果:

hello, world
hello, world

析构要领

  • 当一个对象没有被任何变量援用时就会自动烧毁,并在被烧毁前自动挪用析构函数,不管递次有无完毕,只需一个对象没有被任何变量援用就会被烧毁。
  • 当PHP递次运转完毕后,一切的对象都会被烧毁,对象在被烧毁前,会自动挪用析构函数。
  • 默许状况下,析构函数烧毁对象的递次和建立对象的递次恰好相反。最早建立的对象末了被烧毁,强调默许状况下是因为,我们可以手动烧毁对象,如许的话对象烧毁的递次就和默许状况不一样了,当PHP递次实行完后,那时刻烧毁对象的要领就是采纳的默许要领。
  • 假如我们定义的一个类里特地有个属性是用来衔接数据库的,当我们建立了该类的实例对象,而且用该成员属性衔接数据库后,假如该范例的实例对象占用资本较大,我们每每会在运用后就马上烧毁,虽然该对象能被烧毁,然则该对象的成员属性所衔接的资本却不会被自动烧毁,须要我们本身手动烧毁,这时候,我们可以在析构函数里增添一句封闭数据库衔接的语句就好了(mysql_close(要封闭的资本))。

示例:

class Test {

    public function __construct() {
        echo 'hello, world<br>';
    }

    public function __destruct()
    {
        echo '实行一些接纳资本的操纵<br>';
    }
}

$testObj = new Test();

输出效果:

hello, world
//实行一些接纳资本的操纵

垃圾接纳机制

  • 在PHP中,当一个对象没有任何援用指向它的时刻,就会成为一个垃圾对象,PHP将启用垃圾接纳器将对象烧毁。
  • 在PHP递次退出前,PHP也将启用垃圾接纳器,烧毁对象。

接见润饰符

  • public

    假如没有为要领指定接见润饰符,它将是public。公有的属性或要领可以在类的内部或外部举行接见。

  • protected

    假如一个属性或要领指定接见润饰符为protected,那末被标记的属性或要领只能在类内部接见,被润饰的属性和要领能被子类继续。

  • private

    假如一个属性或要领指定接见润饰符为private,那末被标记的属性或要领只能在类内部接见,私有的属性和要领将不会被继续。

把戏要领

  1. 把戏要领都是在满足某个前提时,由体系自动挪用。

  2. 把戏要领的名字,都是以两个下划线(__)开首的,因而我们在自定义函数时,函数名不要以两个下划线开首。

  3. 一些经常运用的把戏要领

    __construct():
     组织要领
    __destruct():
     析构要领
    __set():
     在给不可接见属性赋值(比方:protected/private/不存在)时,__set()会被挪用。
    __get():
     读取不可接见属性的值(比方:protected/private/不存在)时,__get()会被挪用。
    __isset():
     当对不可接见属性(比方:protected/private/不存在)挪用isset()或empty()时,__isset()会被挪用。
    __unset():
     当对不可接见属性(比方:protected/private/不存在)挪用unset()时,__unset()会被挪用。
    __toString():
     当我们把一个对象当作字符串输出时,就会自动挪用__stoString()要领。
    __clone():
     假如定义了__clone要领,则新建立的对象clone(复制生成的对象)中的__clone()会被挪用。用法以下:
     $copy_of_object = clone $object;
     克隆后的对象与原对象的地点不一样。
     当对象被复制后,PHP 5 会对对象的一切属性实行一个浅复制(shallow copy)。一切的援用属性 依旧会是一个指向本来的变量的援用。
     假如想防备其他递次员克隆某个对象,可以重写__clone()要领并把接见润饰符设置为private。
    __call():
     在对象中挪用一个不可接见(比方函数接见润饰符为protected/private/不存在)要领时,__call()会被挪用。
    __callStatic():
     用静态体式格局中挪用一个不可接见要领时,__callStatic() 会被挪用。

对象比较

当运用比较运算符(==)比较两个对象变量时,比较的原则是:假如两个对象的属性和属性值 都相称,而且两个对象是同一个类的实例,那末这两个对象变量相称。

而假如运用全等运算符(===),这两个对象变量一定要指向某个类的同一个实例(即同一个对象)。

示例:

class Test {

    public $name = 'itbsl';
    public $age  = 25;
}

$testObj  = new Test();
$testObj2 = new Test();

if ($testObj == $testObj2) {
    echo '相称<br>';
} else {
    echo '不相称<br>';
}

$testObj2->name = 'jack';

if ($testObj == $testObj2) {
    echo '相称<br>';
} else {
    echo '不相称<br>';
}

继续

纵然父类的某些属性设置为私有的,子类依旧可以继续,然则对子类倒是不可见的。当子类对象运用父类的私有属性的时刻,会自动触发重载机制,在子类建立一个和父类私有属性同名的属性。此时子类运用的属性并非父类的私有属性了,而是经由过程重载建立的和父类私有属性同名的属性罢了。

假如在子类中须要接见其父类的组织要领( 要领的接见润饰符是public/protected)可以运用父类::要领名(或许 parent::要领名)来完成。(引荐运用parent::要领名,而且平常挪用父类组织要领都是parent::__construct();)

挪用父类的一般要领直接用this->要领名即可。(也可以用父类名::要领名或许 parent::要领名 ,然则不引荐)

继续并非直接把父类的属性和要领直接拷贝到子类内里来。而是建立了一种关联。底本我认为是直接把父类的属性和要领直接拷贝过来,末了发明只是建立了一种关联。下图证明了不是直接拷贝,当在子类里挪用父类的要领时,父类输出本身的属性时输出效果都和初始化不一样了(private属性除外,因为是私有的,子类没法瞥见,所以子类也没法重写父类的私有属性),假如是直接拷贝的话,那末当挪用父类的要领时应当输出100,200,300才对,所以说继续不是直接拷贝。

class A {

    public    $num1 = 100;
    protected $num2 = 200;
    private   $num3 = 300;

    public function show1() {
        echo 'num1 = ' . $this->num1 . '<br>';
    }

    public function show2() {
        echo 'num2 = ' . $this->num2 . '<br>';
    }

    public function show3() {
        echo 'num3 = ' . $this->num3 . '<br>';
    }
}

class B extends A {

    public    $num1 = 1;
    protected $num2 = 2;
    private   $num3 = 3;

    public function show1() {
        echo 'num1 = ' . $this->num1 . '<br>';
        parent::show1();
    }

    public function show2() {
        echo 'num2 = ' . $this->num2 . '<br>';
        parent::show2();
    }

    public function show3() {
        echo 'num3 = ' . $this->num3 . '<br>';
        parent::show3();
    }
}

$bObj = new B();
$bObj->show1();
$bObj->show2();
$bObj->show3();

输出效果:

num1 = 1
num1 = 1
num2 = 2
num2 = 2
num3 = 3
num3 = 300

重载

PHP所供应的"重载"(overloading)是指动态地"建立"类属性和要领。我们是经由过程把戏要领(magic methods)来完成的。

当挪用当前环境下未定义或不可见的类属性或要领时,重载要领会被挪用。本节背面将运用"不可接见属性(inaccessible properties)"和"不可接见要领(inaccessible methods)"来称谓这些未定义或不可见的类属性或要领。

属性重载只能在对象中举行。在静态要领中,这些把戏要领将不会被挪用。所以这些要领都不能被声明为 static。从 PHP5.3.0 起, 将这些把戏要领定义为 static 会发生一个正告。

一切重载要领都必需被声明为public。

这些把戏要领都参数都不能经由过程援用通报。

PHP中的"重载"与别的绝大多数面向对象言语差别。传统的"重载"是用于供应多个同名的类要领,但各要领的参数范例和个数差别。

因为PHP处置惩罚赋值运算的体式格局,__set()的返回值将被疏忽。相似的,在下面如许的链式赋值中,__get()不会被挪用。

$a = $obj->b = 8;

在除 isset() 外的别的言语构造中没法运用重载的属性,这意味着当对一个重载的属性运用 empty() 时,重载把戏要领将不会被挪用。

为避开此限定,必需将重载属性赋值到当地变量再运用 empty()。

//在对象中挪用一个不可接见要领时,__call() 会被挪用。
public mixed __call(string $name , array $arguments)

//用静态体式格局中挪用一个不可接见要领时,__callStatic() 会被挪用。
public static mixed __callStatic(string $name , array $arguments)

属性重载

我们曾提过,当我们接见或给一个不可接见(protected/private)的属性或许不存在的属性赋值时,就会挪用响应的体系把戏要领__get($property)__set($property, $value),假如我们不重写这两个要领,当我们给不存在的属性赋值时,体系会自动帮我们建立一个public的属性,我们可以本身重写这两个要领来治理这些这些动态建立的属性。或许直接不让发生动态属性。当我们不重写这两个要领就不可接见属性赋值时,会报致命毛病。

示例:

class Obj {

    protected $name = 'itbsl';



}

$obj = new Obj();
$obj->name = "jack"; //此处会报致命毛病

var_dump($obj);

毛病信息为:

Fatal error: Uncaught Error: Cannot access protected property Obj::$name

当我们重写了__set()要领就没问题了

class Obj {

    protected $str = 'itbsl';

    public function __set($name, $value)
    {
        $this->$name = $value;
    }

}

$obj = new Obj();
$obj->str = "jack";

var_dump($obj);

属性重载可以协助我们动态治理新的属性也可以制止动态建立属性。

(1)动态治理

class Dog {

    //定义一个数组,治理我们动态增添的属性和值
    private $arr = [];
    
    //这里我们重写__set来治理动态增添的属性
    public function __set($name, $value)
    {
        $this->arr[$name] = $value;
    }
    
    public function __get($name)
    {
        return isset($this->arr[$name]) ? $this->arr[$name] : null;
    }
}

(2)制止建立动态属性。重写set要领,内里什么也不做。

class Dog {
    
    //这里我们重写__set来治理动态增添的属性
    public function __set($name, $value)
    {
       //just do nothing
    }  
}

要领重写

在子类中重写父类的要领时要,重写的要领的接见掌握符不能比父类的要领的接见掌握符的级别小。比方:假如父类的接见掌握符为public,则子类重写要领的接见润饰符只能为public,假如父类的为protected,则子类的接见润饰掌握符可认为protected或public。重写属性也要恪守上面的划定规矩

属性重写

假如子类有和父类雷同的属性,假如属性是public或许protected则会重写父类的属性,假如是private则建立一个同名的新私有属性,同时依旧会继续父类的同名私有属性。

静态属性

  1. 静态属性不属于某个对象,而是一切对象同享的属性,每一个对象都可以接见它。
  2. 静态属性属于类的领域,而不是某个对象的独占特征。
  3. 在类中,运用和接见静态变量的体式格局是 self::$静态属性
  4. 在类外,运用和接见静态变量的体式格局是 类名::$静态属性(请求接见润饰符为public)。
  5. 当我们用var_dump()输出一个对象的时刻,该对象的静态变量不会被输出。
  6. 就像别的一切的 PHP 静态变量一样,静态属性只能被初始化为笔墨或常量,不能运用表达式。所以可以把静态属性初始化为整数或数组,但不能初始化为另一个变量或函数返回值,也不能指向一个对象。

静态要领

  1. 静态要领的接见体式格局为 类名::静态要领名(); 同时也可以用对象名->静态要领名();和对象名::静态要领名(),然则后两种不引荐,只管只用第一种。
  2. 在类的外部挪用静态要领,请求静态要领的接见润饰符必需是public的。
  3. 在类内部挪用静态要领: self::静态要领 或许 类名::静态要领 经由过程$this也可以。只引荐第一种体式格局。在类的内部接见静态要领,不管是什么润饰符都可以接见静态要领。
  4. 静态要领中不可以接见非静态属性和非静态要领。
  5. 一般的成员要领,可以接见静态属性。

静态属性和一般属性的区分:

(1)加上static称静态变量,不然就是一般属性

(2)静态属性是与类相干的,一切对象同享的属性

(3)一般属性属于每一个对象个别的属性。

多态

因为PHP变量没有范例限定,所以PHP是天生支撑多态的。

范例束缚

范例束缚支撑的范例有 array 、 callable 、 对象范例 、 接口

笼统类

当父类的一些要领不能确定时,可以用abstract症结字来润饰该要领[笼统要领],用abstract来润饰该类[笼统类]。

(1) 假如你愿望把某个要领做成 笼统要领 ,则前面写上 abstract

(2) 假如一个类中有笼统要领,那末该类必需声明为笼统类。

(3) 笼统类最重要的作用在于设想,它的目标是让别的的类继续它,并完成个中的笼统要领。假如子类继续了该笼统类,除非继续该笼统类的子类也被声明为笼统类,不然必需完成笼统类中一切的笼统要领,假如不完成就会报错。

(4) 笼统类不能被实例化

(5) 笼统类可以没有abstract要领

(6) 笼统类可以有非笼统要领,成员属性和常量

(7) 笼统要领不能有函数体

基础语法:

abstract class 类名 {
    abstract 润饰符 function 函数名(参数列表);
}

一般类怎样继续笼统类?

abstract class Superman {
    public $name;
    public $age;
    
    public function __construct($name, $age) {
        
        $this->name = $name;
        $this->age  = $age;
    }
    
    abstract public function run();
    abstract public function fly();
    abstract public function attach();
}

class Spiderman extends Superman {
    
    public function run()
    {
        echo 'Spiderman is running on the net.<br>';
    }
    
    public function fly()
    {
        echo 'Spiderman can hang in the sky through net.<br>';
    }
    
    public function attach()
    {
        echo 'Spider attach.<br>';
    }
}

接口

(1) 接口就是给出一些没有完成的要领,封装到一同,到某个类要运用的时刻,再根据具体状况把这些要领写出来。

(2)基础语法:

interface 接口名 {
    //要领[不含要领体]
}

(3)接口中一切的要领都不能有主体

(4)一个类可以完成多个接口,接口名之间用逗号离隔

class 类名 implements 接口1, 接口2 {
    
}

(5)接口中可以有属性,但只能是常量,而且是公然可接见的。默许是public,但不能用public显式润饰

(6)接口中的要领都必需是public的,默许就是public

(7)一个接口不能继续别的的类,然则可以继续别的接口,而且一个接口可以继续多个接口

interface 接口名 extends 接口1, 接口2 {
    //要领[不含要领体]
}

(8)接口不能被实例化

(9)接口是越发笼统的笼统类,接口里的一切要领都没有要领体。接口表现了递次设想的多态和高内聚低耦合的设想头脑。

(10)申明:

接口的定名范例平常是字符 i 开首,然后第二个字符大写,情势如:iXxxx,比方:iUsb

(11)怎样运用接口中的常量

接口名::常量名;

假如某个类要完成接口,须要用implements 症结字。而且完成接口里的一切要领,假如该类要完成多个接口,则一切的接口的一切的要领都要完成,只需存在没有完成的接口里的要领就会报错。

示例:

interface Displayable {
    function display();
}

class Base {
    function operation() {
        echo 'operate something.<br>';
    }
}

class SubClass extends Base implements Displayable {

    function display()
    {
        echo 'display.<br>';
    }
}

$temp = new SubClass();
$temp->display();

final症结字

(1) 作用:

因为平安的斟酌,类的某个要领不允许子类经由过程重写来修正。

不愿望某个类被别的的类继续。

(2) PHP5新增了一个final症结字。假如父类中的要领被声明为final,则子类没法掩盖该要领。假如一个类被声明为final,则该类不能被继续。

(3) final不可以润饰成员属性(变量)

(4) final要领不能被重写,但可以被继续。纵然是被声明为final的要领也依旧可以被继续并被运用,只是不能重写(修正)罢了。

(5) 平常来说,final类中不会涌现final要领,因为final类都不能被继续,也就不会去重写override final类的要领了。

(6) final类是可以被实例化的

类常量

可以把在类中始终保持稳定的值定义为常量。在定义和运用常量的时刻不须要运用 $ 标记。

常量的值必需是一个定值,不能是变量、类属性、数学运算的效果或函数挪用。

接口(interface)中也可以定义常量。更多示例见文档中的接口部份。

自 PHP 5.3.0 起,可以用一个变量来动态挪用类。但该变量的值不能为症结字(如 selfparentstatic)。

细节申明:

(1) 常量名平常字母悉数大写:TAX_RATE,中心可以有下划线

(2) 在定义常量的同时,必需赋初值,比方 const TAX_RATE = 1.1

(3) const症结字前不能用public/protected/private润饰。默许是public

(4) 接见常量

在类的外部 类名::常量名 接口名::常量名

在类的内部 类名::常量名 self::常量名

(5) 常量的值在定义的时刻就初始化,今后就不能修正

(6) 常量可以被子类继续

(7) 一个常量是属于一个类的,而不是某个对象的。

(8) 常量是全局性的,可以在任何地方接见。

(9) 在类内里不能用define定义常量。

(10) 常量的值可以是基础范例数据和数组。不可以是对象。

对象遍历

foreach用法和之前的数组遍历是一样的,只不过这里遍历的key是属性名,value是属性值。在类外部遍用时,只能遍历到public属性的,因为别的的都是受庇护的,类外部不可见。

示例:

class HardDiskDrive {

    public $brand;
    public $color;
    public $cpu;
    public $workState;

    protected $memory;
    protected $hardDisk;

    private $price;

    public function __construct($brand, $color, $cpu, $workState, $memory, $hardDisk, $price) {

        $this->brand = $brand;
        $this->color = $color;
        $this->cpu   = $cpu;
        $this->workState = $workState;
        $this->memory = $memory;
        $this->hardDisk = $hardDisk;
        $this->price = $price;
    }

}

$hardDiskDrive = new HardDiskDrive('希捷', 'silver', 'tencent', 'well', '1T', 'hard', '$456');

foreach ($hardDiskDrive as $property => $value) {

    var_dump($property, $value);
    echo '<br>';
}

输出效果为:

string(5) "brand" string(6) "希捷" 
string(5) "color" string(6) "silver" 
string(3) "cpu" string(7) "tencent" 
string(9) "workState" string(4) "well"

假如我们想遍历出对象的一切属性,就须要掌握foreach的行动,就须要给类对象,供应更多的功用,须要继续自Iterator的接口:

该接口,完成了foreach须要的每一个操纵。foreach的实行流程以下图:

看图例中,foreach中有几个症结步骤:5个。

而Iterator迭代器中所请求的完成的5个要领,就是用来协助foreach,完成在遍历对象时的5个症结步骤:

当foreach去遍历对象时, 假如发明对象完成了Ierator接口, 则实行以上5个步骤时, 不是foreach的默许行动, 而是挪用对象的对应要领即可:

示例代码:

class Team implements Iterator {

    //private $name = 'itbsl';
    //private $age  = 25;
    //private $hobby = 'fishing';

    private $info = ['itbsl', 25, 'fishing'];

    public function rewind()
    {
        reset($this->info); //重置数组指针
    }

    public function valid()
    {
        //假如为null,示意没有元素,返回false
        //假如不为null,返回true

        return !is_null(key($this->info));
    }

    public function current()
    {
        return current($this->info);
    }

    public function key()
    {
        return key($this->info);
    }

    public function next()
    {
        return next($this->info);
    }

}

$team = new Team();

foreach ($team as $property => $value) {

    var_dump($property, $value);
    echo '<br>';
}

PHP内置规范类

假如我们愿望把一些数据,以对象的属性的体式格局存储,同时我们又不想定义一个类,可以斟酌运用PHP内置规范类stdClass[standard规范]

基础用法:

//注重: stdClass()不是我们自定义的类,而是PHP内置的
$person = new stdClass();

然后我们就可以直接用$person->属性的体式格局来运用,属性都不是体系的,我们本身也没定义,然则当我们运用这个属性的时刻,体系发明没有定义就会挪用重载要领,重载这个属性。自动帮我们建立这个属性。

别的数据范例转成对象

假如,我们愿望把非对象范例转换成对象,可以经由过程以下要领完成,(object)来强迫转换,把这些数据转换成规范内置类stdClass,此种转换不转变原有数据范例

【引荐课程:PHP视频教程】

以上就是PHP面向对象特征的细致内容,更多请关注ki4网别的相干文章!

标签:PHP面向对象