资讯专栏INFORMATION COLUMN

php.类与对象

scq000 / 3166人阅读

摘要:接口可以使用常量,叫接口常量,和类的常量使用方法相同类可以同时继承多个接口使用接口常量抽象类不能被实例化。继承抽象类,子类必须实现父类中所有的抽象方法。

访问控制

属性和方法的访问控制(可见标识):
public 任何地方
private 类自身
protected 类自身,自子类及自父类

this

this 可以理解为这个类的一个实例

self

self 代表类本身

__construct

实例化时就会自动执行
public function __construct() {}

__destruct

当对象对销毁时自动执行
public function __destruct(){}

类常量

定义合不可改变

const ONE = 1
const TWO = self::ONE + 1;

可以在类外部调用
Class::Two

parent

parent代表父类
public function __construct(){ parent::__construct();}

final

final class Dad(){} 加到类定义前面表示Dad类不想被继承

class Dad(){
    final public function run(){}  // 加到方法声明前面,表示方法不想被子类重写
}
namespace

namespace必须放在代码文件的第一行
受命名空间影响的类型:类(包括抽像类,traits)、接口、函数和常量。
当没有使用namespace关键字指定命名空间时,当前脚本是存在于全局命名空间的。用表示。Class1
类全在指定的命名空间去查找,没找到则抛出错误。
函数与常量,在指定命名空间查找,没找到则到全局命名空间查找,还没打到则抛错。

函数

ns1 s2fn()

常量

define定义的常量是全局的,不受命名空间影响。
const定义的常量受命名空间影响。

namespace ns1
s2;
const ONE = 1;

echo ns1
s2ONE;
use 导入类

use导入命名空间下的类
use ns1 s2class1;

as重命名导入的类
use ns1 s2class1 as class2;

导入函数

use function ns1 s2fn as fn1;

导入常量

use const ns1 s2ONE;

自动加载 __autoload
function __autoload($className){ require $className . ".php";}
spl_autoload_register 传匿名函数
spl_autoload_register(function($className){ require $className . ".php"; });
传函数名
function test($className){ require $className . ".php"; }
spl_autoload_register("test");
传类
class Momo
{
   function autoload($className)
   {
           require $className . ".php";
   }
}

spl_autoload_register([new Momo, "autoload"]);
static

声明静态属性和静态方法,不经过实例化,通过类名即可调用。

class Person()
{
    public static $hand = "手";
   
   public static function run()
   {
           echo "running...";
   }
}

echo Person::$hand;
Person::run();

类内部调用静态属性和静态方法用self关键字

echo self::$hand; self::run();

调用父类的静态属性和静态方法用parent关键字

echo parent::$hand; parent::run();

后期静态绑定
class A
{
    public static function who()
   {
           echo "A类的who方法";
   }
   
   public static function test1()
   {
           self::who();
   }
   
   public static function test2()
   {
           static::who();
   }
}

class B extends A
{
    public static function who()
    {
        echo "B类的who方法";
    }
}

B::test1();  // test1内部用的self,调用的是自身(A类)的静态方法
B::test2();  // 后期绑定。内部用static,根据后期的调用环境确定,调用的是B类的静态方法
魔术方法 __set
class Test
{
    private $name = "";
    
    public function __set($var, $val)
    {
        //     对$val进行数据处理
        $this->$var = $val;
    }
}

$test = new Test();
$test->name = "tom";    // 赋值tom
__get
class Test
{
    private $name = "jack";
    public function __get($var)
    {
        return $this->$var;
    }
}

$test = new Test();
echo $test->name;    // jack
__isset

用于检测私有属性是否存在

class Test
{
    private $name = "mary";
    
    public function __isset($var)
    {
        return isset($this->$var);
    }
}
$test = new Test();
var_dump($test->name);    // 如果不设置__isset,返回false,设置后返回true
__unset

用于删除私有属性

class Test
{
    private $name = "Levi";
   public function __unset($var)
   {
           unset()
   }
}
$test = new Test;
unset($test->name);        // 会触发__unset
__call

避免调用一个不存在的方法时产生错误,当调用的方法不存在时,__call方法会自动调用

class Test
{
    public function __call($fn_name, $fn_arguments)
    {
        echo $fn_name;
        print_r($fn_arguments);
    }
}

$test = new Test();
$test->go(1, "ok");        // 自动调用`__call`方法,打印出函数名和参数数组
__callStatic

__call类似
避免调用一个不存在的静态方法

class Test
{
    public static function __callStatic($fn_name, $fn_arguments)
    {
        echo $fn_name;
        print_r($fn_arguments);
    }
}

// `__callStatic` 必须声明为静态方法
Test::go(1, "ok");
__invoke

当对象以函数的形式调用的时候,自动调用__invoke方法

class Test
{
    public function __invoke($args)
    {
        return $args;
    }
}
$test = new Test();
$test("go.....");    // 运行__invoke
__toString

当打印对象是会调用__toString方法

class Test
{
    public function __toString()
    {
        return "Hello world!";
    }
}

$test = new Test;
echo $test;        // 输出 Hello world!
对象复制 浅拷贝

比较省内存,对象的拷贝默认是浅拷贝。

$a = new Test();
$b = $a;    // 浅拷贝。传址。改变$b。$a也会改变。

对象的复制是浅拷贝的。传址。
普通变量的拷贝是深拷贝的。传值。

深拷贝
$a = new Test();
$b = clone $a;    // 深拷贝。改变$b,不会改变$a。
__clone

当使用clone关键字时,自动调用__clone方法

class Test
{
    public $obj = null;
    public function __clone()
    {
        $this->obj = clone $this->obj;
    }
}
class Person
{
    public $sex = 0;
}
$a = new Test;
$a->obj = new Person;
$b = clone $a;        // 触发`__clone` 对obj进行深拷贝
$b->obj->sex = 1;    // $b中的obj对象改变了。而$a中的obj对象没变。
类型约束
class A
{
    public function go()
    {
        echo "go .....";
    }
}
function test(A $a) {
    $a->go();
}
test(new A());
Trait

单继承语言PHP的代码复用机制。

Trait Bt
{
    public function atest()
    {
        echo "Hello ";
    }
    
    public function btest()
    {
        echo "world";
    }
    
    public function ab()
    {
        $this->atest();
        $this->btest();
    }
}

class Test
{
    use Bt;        // 使用Bt Trait,便拥有了Bt所有的方法
}

$test = new Test;
$test->ab();

继承多个Trait

Trait A
{
    public $name = "tom";
    public function a()
    {
        echo "Hello ";
    }
}
Trait B
{
    public function b()
    {
        echo "world ";
    }
}

class Test
{
    use A,B;
    public function c()
    {
        echo $this->name;
    }
}

$test = new Test;
$test->a();
$test->b();
$test->c();        // Hello world tom

Trait 支持嵌套

Trait A{}
Trait B{}
Trait C
{
    use A,B;
}
Class Test
{
    use C;
}
interface

接口是类的模板。在接口中只定义需要实现的空方法,这些方法在接口中不做具体实现。
接口是不能被实例化的。

Interface Person
{
    public function eat();
   public function sleep();
}

class man implements Person
{
    public function eat()
    {
        echo "eating...";
    }
    
    public function sleep()
    {
        echo "sleeping...";
    }
}

class L
{
    public static function factory(Person $user)    // 用接口作类型约束
    {
        return $user;
    }
}

$user = L::factory(new Man());
$user->eat();
$user->sleep();

接口可以继承接口。
接口可以继承多个接口。
接口可以使用常量,叫接口常量,和类的常量使用方法相同

Interface Ia
{
    const ONE = 1;
    public function eat();
}

Interface Ib
{
    public function sleep();
}

Interface AB extends Ia,Ib
{}

// class Test implements Ia,Ib        类可以同时继承多个接口
class Test implements AB
{
    public function eat()
    {
        echo "eating...";
    }
    
    public function sleep()
    {
        echo "sleeping...";
    }
}

$test = new Test;
$test->eat();
$test->sleep();
echo Ia::ONE;    // 使用接口常量
abstract

抽象类不能被实例化。
如果至少有一个方法被声明为抽象的,那么这个类必须被声明为抽象的。
抽象方法只能声明,不能有具体功能实现。
抽象类可以有被实现的的方法。

继承抽象类,子类必须实现父类中所有的抽象方法。
这些方法的访问控制必须和父类一样,或者更宽松,不能比父类更严格。
方法的调用方式也必须匹配。类型和参数数量必须一致,但子类可以定义父类中不存在的可选参数。

abstract AB
{
    public function run()
    {
        echo "running...";
    }
    
    abstract public function eat();
    abstract public function sleep();
}

class Test extends AB
{
    public function eat()
    {
        echo "eating...";
    }
    
    public function sleep($time = "21:00 PM")    // 可以定义父类方法中不存在的可选参数
    {
        echo "sleep @ " . $time;
    }
}
单例模式

只能被实例化一次,节省内存空间

class Test
{
    private static $instance = null;
   private function __constrct()
   {}
   private function __clone()
   {}
   public static function getInstance()
   {
           if (!(self::instance instanceof self)) {
              self::instance = new self();          
        }
           return self::instance;
   }
}

$test = Test::getInstance();    // 多次调用也只是实例化一次
工厂模式
Interface CacheI
{
    public function set($key, $value);
   public function get($key);
   public function delete($key);
}
class Memcache implements CacheI
{
    public function set($key, $value){}
   public function get($key){}
   public function delete($ke){}
}
class Redis implements CacheI
{
    public function set($key, $value){}
   public function get($key){}
   public function delete($ke){}
}
class Cache
{
    public static function factory()
    {
        return new Memcache();    // 这里可以是继承了CacheI接口的任何类,比如Redis
    }
}
$cache = Cache::factory();
$cache->set("name", "tom");
$cache->get("name");
$cache->delete("name");

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/29698.html

相关文章

  • php面向对象详解

    摘要:前言自从进入版本以来,开始全面地支持面向对象编程。好了,进入正题,面向对象的三大特性分别是封装性,继承性以及多态性,使用面向对象开发,让我们的程序可维护以及扩展性大大提高。 showImg(https://segmentfault.com/img/remote/1460000012257579?w=1920&h=1080); 前言 自从php进入5.0版本以来,PHP开始全面地支持面向...

    xingpingz 评论0 收藏0
  • php易错笔记-类与对象,命名空间

    摘要:类与对象基本概念如果在之后跟着的是一个包含有类名的字符串,则该类的一个实例被创建。如果该类属于一个名字空间,则必须使用其完整名称。如果一个类被声明为,则不能被继承。命名空间通过关键字来声明。 类与对象 基本概念 new:如果在 new 之后跟着的是一个包含有类名的字符串,则该类的一个实例被创建。如果该类属于一个名字空间,则必须使用其完整名称。 Example #3 创建一个实例 ...

    MartinHan 评论0 收藏0
  • 【modernPHP专题(4)】抽象类与接口

    摘要:抽象类支持抽象类和抽象方法。接口是一种特殊的抽象类,这种抽象类中只包含抽象方法和静态常量。对抽象类的使用是通过关键字。抽象类中可以声明各种类型成员变量,实现数据的封装。一个类可以同时实现多个接口,但一个类只能继承于一个抽象类。 抽象类 php5支持抽象类和抽象方法。类前加 abstract, 此类就成为抽象类,无法被实例化,此类天生就是用来被继承的,给子类提供了一个类的模板;类方法前加...

    Keven 评论0 收藏0
  • PHP面试常考内容之面向对象(3)

    摘要:面试专栏正式起更,每周一三五更新,提供最好最优质的面试内容。继上一篇面试常考内容之面向对象发表后,今天更新面向对象的最后一篇。面向对象的主要特征为封装继承多态。为了提高内聚性减少引起变化,单一原则是低耦合高内聚的面向原则上的引申。 PHP面试专栏正式起更,每周一、三、五更新,提供最好最优质的PHP面试内容。继上一篇PHP面试常考内容之面向对象(2)发表后,今天更新面向对象的最后一篇(3...

    xfee 评论0 收藏0
  • PHP代码优化— getter 和 setter

    摘要:同时也可以用来实现委托,委托是指一个对象转发一个请求给另一个对象,把请求的处理委托给另一个对象。但在继承是父类与子类的关系是固定的,而使用委托可以在运行时改变使用的对象,委托比继承具有更大的灵活性。 PHP中要实现类似于Java中的getter和setter有多种方法,比较常用的有: 直接箭头->调用属性(最常用),不管有没有声明这个属性,都可以使用,但会报Notice级别的错误 $d...

    hzc 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<