最近在准备面试,复习了一下基础,包括PHP的类与对象。
1.类是一种抽象定义,对象是一种实现。
#定义类
class object
{
}
#实现类(对象)
new object
2.类中包括属性与方法
访问控制(可见性)
class object
{
#可在内部调用,可被子类调用,可被外部(对象)调用
public $a;
#可在内部调用,可被子类调用
protected $b;
#可在内部调用
private $c;
}
3.类的自动加载
类的自动加载,之前是使用__autoload(),现在,倾向于使用 spl_autoload_register() 注册器,实现懒加载
‘__’开头的为php中的语法糖
spl_autoload_register(function ($class){
echo $class;exit;
include $class . '.php';
});
new $a;
#输入
#a
4.对象继承
继承一个类,就会继承父类的属性与方法(private可见性除外),如果不覆盖父类的属性和方法,则会全部继承。
class parent_class
{
public $a;
public function func_a($arg)
{
echo 'hello' . $arg;
}
}
class son extends parent_class
{
}
$model = new son();
$model->func_a('liuser');
#输出
#hello liuser
# 重写子类
class son extends parent_class
{
public function func_a($arg)
{
echo '你好' . $arg;
}
}
$model = new son();
$model->func_a('liuser');
#输出
#你好 liuser
#调用子类自己的属性
abstract class dbObject
{
const TABLE_NAME='undefined';
public static function GetAll()
{
# 这里使用$c或者static都可以
$c = get_called_class();
return "SELECT * FROM `".static::TABLE_NAME."`";
}
}
class dbPerson extends dbObject
{
const TABLE_NAME='persons';
}
class dbAdmin extends dbPerson
{
const TABLE_NAME='admins';
}
echo dbPerson::GetAll()."<br>";//output: "SELECT * FROM `persons`"
echo dbAdmin::GetAll()."<br>";//output: "SELECT * FROM `admins`"
5.抽象类
抽象类用abstract表示,当一个类中有一个方法为抽象,则类必须被定义为抽象类,抽象类不能被实例化,只能被继承
抽象类中的方法只是定义其形式,不实现具体方法。
abstract class absclass
{
#只能写方法名和参数,不能写具体实现(没有{}方法体)
abstract protected function say($name);
abstract public function run();
}
class class_1 extends absclass
{
#这里的可见性级别只能比父类更开发,protected或者public,不能使用private
protected function say($name)
{
// TODO: Implement say() method.
}
public function run()
{
// TODO: Implement run() method.
}
}
6.对象接口
接口(interface),规则类必须实现的方法,但不需要定义内容,同抽象类相似。
接口中定义的所有方法都必须是公有,这是接口的特性。
接口中的常亮不能被子类覆盖。
抽象中,只有抽象类中的抽象方法必须实现,接口中,只要定义为接口,就必须全部实现。
定义接口:interface
实现接口:implements
interface template
{
public function setVariable($name, $var);
public function getHtml($template);
}
class template1 implements template
{
public function setVariable($name, $var)
{
// TODO: Implement setVariable() method.
}
public function getHtml($template)
{
// TODO: Implement getHtml() method.
}
}
多重继承
interface a
{
public function foo();
}
interface b
{
public function bar();
}
interface c extends a, b
{
public function baz();
}
class d implements c
{
public function baz()
{
// TODO: Implement baz() method.
}
public function bar()
{
// TODO: Implement bar() method.
}
public function foo()
{
// TODO: Implement foo() method.
}
}
7.trait(特性)
自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait,说白了就是定义一个trait,然后在需要用到的类中使用use调用其。
特点:
1.实现代码复用,解决多重继承问题。
2.无法被实例化
想象一下,如果你需要在一个类中加上日志的相关方法,会怎么做呢?继承?如果有多个类都需要实现日志的方法呢?
如果需要继承,则违背了继承的原则,除非你的类是和日志相关。可以考虑使用特性解决。
trait log
{
#记录日志
public function start()
{
echo time();
}
public function end()
{
echo time();
}
}
class Car
{
#使用特性log
use log;
}
$model = new Car();
$model->start();
$model->end();
使用use就是当trait中的方法复制到当前的类对象中,可能会产生问题。
比如log中定义了start,而car中也定义了start,则会产生一个优先级的问题,官方给出的优先级如下:
优先顺序是当前类中的方法会覆盖 trait 方法,而 trait 方法又覆盖了基类中的方法。
9.重载
动态的创建类方法或属性,使用魔法方法__set __get,注意一下用法。
1.魔术方法的可见性必须是public.
2.如果类方法可类变量存在,则无法使用.
class test
{
private $data = [];
public function __set($name, $value)
{
$this->data[$name] = $value;
}
public function __get($name)
{
if($this->data[$name]){
return $this->data[$name];
}
echo '变量' . $name . '不存在';
}
}
$model = new test();
$model->name = 'liuser';
echo $model->name;
10. final
定义:如果父类中的方法被声明为 final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承。
这个很好了解,就不展开了,具体可以点开下面的链接
11.clone(克隆)
使用clone克隆一个对象,会把其进行浅复制。有一些特点
1.因为是浅复制,所以对象的引用还是会指向对象之前的引用。
2.如果对象定义了__clone魔术方法,则在复制完成后会执行__clone
3.如果类需要定义为单例模式时,则需要防止被克隆,在__clone 方法写入exit。
class c1
{
public $instance = 0;
public function __clone()
{
$this->instance = $this->instance +1 ;
}
public function say()
{
echo 'hello';
}
}
$m1 = new c1();
$m2 = clone $m1;
echo $m1->instance;
echo $m2->instance;
输出: 0 1
12.类型约束
在函数的参数执行参数所属的类型,包括对象、数组、接口
class c1
{
public function say(){}
}
class c2
{
#指定必须为c1的一个对象
public function f1(c1 $object)
{
$object->say();
}
#指定必须为一个数组
public function f2(array $list)
{
return $list['k1'];
}
#指定必须为一个回调函数
public function call(callable $call,$data)
{
call_user_func($call,$data);
}
}
13.对象与引用
PHP 的引用是别名,就是两个不同的变量名字指向相同的内容。在 PHP 5,一个对象变量已经不再保存整个对象的值。只是保存一个标识符来访问真正的对象内容。 当对象作为参数传递,作为结果返回,或者赋值给另外一个变量,另外一个变量跟原来的不是引用的关系,只是他们都保存着同一个标识符的拷贝,这个标识符指向同一个对象的真正内容
class A {
public $foo = 1;
}
$a = new A;
# $a ,$b都是同一个标识符的拷贝
$b = $a;
$b->foo = 2;
echo $a->foo."\n";
#结果等于2
14.序列化对象
所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。unserialize()函数能够重新把字符串变回php原来的值。 序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。
注意:如果反序列化,然后调用对象中的方法,则在之前,必须引入该类.
虽然在序列化的时候,不会保存对象的方法,但是在反序列化后,依然可以使用对象中的方法。
class A {
public $foo = 1;
public function say()
{
echo 'hello';
}
}
$a = new A();
$s_a = serialize($a);
#结果 : O:1:"A":1:{s:3:"foo";i:1;}
$b = unserialize($s_a);
var_dump($b);
#object(A)#2 (1) {
#["foo"]=>
# int(1)
#}
$b->say();
#结果 hello
echo $b->foo;
#结果 1