__construct()
__set()
__get()
__isset()
__unset()
__autoload()
__call()
__clone()
__invoke()
__sleep()
__wakeup()
__construct()
构造方法: 在PHP中的构造方法要求不能进行构造方法的重载,即构造 方法只有一个.
function __construct($name="宋", $sex="", $age=1) { //构造方法在对象诞生时为成员属性赋初值
$this->name=$name;
$this->sex=$sex;
$this->age=$age;
}
说明:
1. 在一个类中,它只可能有一个构造方法.
2. 所默认的构造方法是public的,如果使用private的话,则会构成单例模式.
一般来说,总是把类的属性定义为private,这更符合现实的逻辑。但是,对属性的读取和赋值操作是非常频繁的,因此在PHP5中,预定义了两个函数“__get()”和“__set()”来获取和赋值其属性,以及检查属性的“__isset()”和删除属性的方法“__unset()”。
//__get()方法用来获取私有属性
private function __get($property_name)
{
if(isset($this->$property_name))
{
return($this->$property_name);
}else
{
return(NULL);
}
}
//__set()方法用来设置私有属性
private function __set($property_name,$value)
{
$this->$property_name=$value;
}
__get()方法:这个方法用来获取私有成员属性值的,有一个参数,参数传入你要获取的成员属性的名称,返回获取的属性值,这个方法不用我们手工的去调用,因为我们也可以把这个方法做成私有的方法,是在直接获取私有属性的时候对象自动调用的。因为私有属性已经被封装上了,是不能直接获取值的(比如:“echo $p1->name”这样直接获取是错误的),但是如果你在类里面加上了这个方法,在使用“echo $p1->name”这样的语句直接获取值的时候就会自动调用__get($property_name)方法,将属性name传给参数$property_name,通过这个方法的内部执行,返回我们传入的私有属性的值。如果成员属性不封装成私有的,对象本身就不会去自动调用这个方法。
<?php
class Person
{
//下面是人的成员属性, 都是封装的私有成员
private $name; //人的名子
private $sex; //人的性别
private $age; //人的年龄
//__get()方法用来获取私有属性
private function __get($property_name)
{
echo "在直接获取私有属性值的时候,自动调用了这个__get()方法<br>";
if (isset($this->$property_name))
{
return ($this->$property_name);
}
else
{
return (NULL);
}
}
//__set()方法用来设置私有属性
private function __set($property_name,$value)
{
echo"在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值<br>";
$this->$property_name=$value;
}
}
$p1=new Person();
//直接为私有属性赋值的操作, 会自动调用__set()方法进行赋值
$p1->name="张三";
$p1->sex="男";
$p1->age=20;
//直接获取私有属性的值, 会自动调用__get()方法,返回成员属性的值
echo"姓名:".$p1->name."<br>";
echo"性别:".$p1->sex."<br>";
echo"年龄:".$p1->age."<br>";
?>
在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值
在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值
在直接获取私有属性值的时候,自动调用了这个__get()方法
姓名:张三
在直接获取私有属性值的时候,自动调用了这个__get()方法
性别:男
在直接获取私有属性值的时候,自动调用了这个__get()方法
年龄:20
private function __isset($nm)
{
echo"当在类外部使用isset()函数测定私有成员$nm时,自动调用<br>";
return isset($this->$nm);
}
private function __unset($nm)
{
echo"当在类外部使用unset()函数来删除私有成员时自动调用的<br>";
unset($this->$nm);
}
<?php
class Person
{
//下面是人的成员属性
private $name; //人的名子
private $sex; //人的性别
private $age; //人的年龄
//__get()方法用来获取私有属性
private function __get($property_name)
{
if (isset($this->$property_name))
{
return ($this->$property_name);
}
else
{
return (NULL);
}
}
//__set()方法用来设置私有属性
private function __set($property_name, $value)
{
$this->$property_name = $value;
}
//__isset()方法
private function __isset($nm)
{
echo "isset()函数测定私有成员时,自动调用<br>";
return isset($this->$nm);
}
//__unset()方法
private function __unset($nm)
{
echo "当在类外部使用unset()函数来删除私有成员时自动调用的<br>";
unset($this->$nm);
}
}
$p1 = new Person();
$p1->name = "this is a person name";
echo var_dump(isset($p1->name)) . "<br>";
echo $p1->name . "<br>";
unset($p1->name);
echo $p1->name;
?>
<?php
include_once "cls/clsA.php";
include_once "cls/clsB.php";
$obj_A = new clsA();
$obj_B = new clsB();
?>
1:加载类文件;
2:实例化类。
<?php
$obj_A = new clsA();
$obj_B = new clsB();
function __autoload($className){
include_once "cls/$className.php";
}
?>
1:创建对象(伪实例)
2:调用__autoload函数,将伪实例的类名传入
3:使用__autoload函数中,预先写好的加载规则进行加载类文件
4:实例化对象(真实实例)
因此,我们可以看出,对于PHP5的autoload函数,必须给定规则,否则一点用没有。
1:__autoload函数是用在类外面,而不是在类里面的函数。(__autoload也是被PHP5保护的关键字之一)
2:完成对__autoload函数加载规则的编码。
如上,当知道A是在cls目录中,而B是在cls/cls目录中。则编写__autoload加载规则就是必要的。
<?php
// PHP5 Used __autoload function
$obj_A = new clsA(); // in "cls" directory!
$obj_B = new clsB(); // in "cls/cls" directory!
function __autoload($className)
{
if (strtolowwer($className) == "clsb")
{
require_once "cls/cls/$className.php";
}
else
{
include_once "cls/$className.php";
}
}
?>
<?php
class TestClass
{
public $foo;
public function __construct($foo) {
$this->foo = $foo;
}
//定义一个__toString方法,返加一个成员属性$foo
public function __toString() {
return $this->foo;
}
}
$class = new TestClass('Hello');
//直接输出对象Cheap Sunglasses
echo $class;
?>
__call( $method, $arg_array ) 当调用一个未定义的方法是调用此访求这里的未定义的方法包括没有权限访问的方法
<?php
//当试图调用类中一个不存在或者不可用的方法时,
//会执行该类中的__call()__call()必须接受两个参数,
//第一个参数存放方法名称,
//第二个参数存放不存在的方法的参数(此参数会放在与该参数同名的数组中)
class callclass
{
function __call($method_name, $p)
{
echo "使用__call尝试调用一个不存在/不可用的成员方法<br>";
echo $method_name;
echo "<pre>";
print_r($p);
echo "</pre>";
}
}
$obj = new callclass();
$obj->method(1, 2, "Hello", "HP");
?>
method
Array
(
[0] => 1
[1] => 2
[2] => Hello
[3] => HP
)
__clone()
PHP5中的对象赋值是使用的引用赋值,如果想复制一个对象则需要使用clone方法,在调用此方法是对象会自动调用__clone魔术方法
如果在对象复制需要执行某些初始化操作,可以在__clone方法实现
<?php
class MyCloneable
{
static $id = 0;
function MyCloneable()
{
$this->id = self::$id + 1; //注意这里如果写self::$id++;将不被充许
}
function __clone()
{
$this->address = "New York";
$this->id = self::$id + 1;
}
}
$obj = new MyCloneable();
$obj->name = "Hello";
$obj->address = "Tel-Aviv";
print $obj->id . "<br>";
$obj1 = clone $obj;
print $obj1->id . "<br>";
print $obj1->name . "<br>";
print $obj1->address . "<br>";
?>
输出:
1
1
Hello
New York
__invoke()
当尝试以调用函数的方式调用一个对象时,__invoke 方法会被自动调用。PHP5.3.0以上版本有效
<?php
class CallableClass
{
public function __invoke($x)
{
var_dump($x);
}
}
$obj = new CallableClass;
$obj(5);
var_dump(is_callable($obj));
?>
int(5)
bool(true)
__sleep()、__wakeup()
__sleep() 串行化的时候用
__wakeup() 反串行化的时候调用
在PHP进行序列化时,serialize() 检查类中是否有 __sleep() , 如果有,则该函数将在任何序列化之前运行。该函数必须返回一个需要进行序列化保存的成员属性数组,并且只序列化该函数返回的这些成员属性. 该函数有两个作用: 第一. 在序列化之前,关闭对象可能具有的任何数据库连接等. 第二. 指定对象中需要被序列化的成员属性,如果某个属性比较大而不需要储存下来,可以不把它写进__sleep要返回的数组中,这样该属性就不会被序列化
相反地,unserialize() 从字节流中创建了一个对象之后,马上检查是否具有__wakeup 的函数的存在。如果存在,__wakeup 立刻被调用。使用 __wakeup 的目的是重建在序列化中可能丢失的任何数据库连接以及处理其它重新初始化的任务。
1)没有__sleep(), __wakeup()
<?php
class User {
public $name;
public $id;
function __construct() {
$this->id = uniqid (); //give user a unique ID 赋予一个不同的ID
}
}
$u = new User ();
$u->name = "HAHA";
$s = serialize ( $u ); //serialize it 串行化 注意不串行化id属性,id的值被抛弃
$u2 = unserialize ( $s ); //unserialize it 反串行化 id被重新赋值
var_dump ( $u );
var_dump ( $u2 );
?>
输出:
object(User)#1 (2) { ["name"]=> string(4) "HAHA" ["id"]=> string(13) "4f69980748589" } object(User)#2 (2) { ["name"]=> string(4) "HAHA" ["id"]=> string(13) "4f69980748589" }
2) __sleep(),serialize序列化"name"
<?php
class User {
public $name;
public $id;
function __construct() {
$this->id = uniqid (); //give user a unique ID 赋予一个不同的ID
}
function __sleep() {
return (array ("name")); //do not serialize this->id 不串行化id
}
}
$u = new User ();
$u->name = "HAHA";
$s = serialize ( $u ); //serialize it 串行化 注意不串行化id属性,id的值被抛弃
$u2 = unserialize ( $s ); //unserialize it 反串行化 id被重新赋值
var_dump ( $u );
var_dump ( $u2 );
?>
输出:
object(User)#1 (2) { ["name"]=> string(4) "HAHA" ["id"]=> string(13) "4f69995eebfb7" } object(User)#2 (2) { ["name"]=> string(4) "HAHA" ["id"]=> NULL }
3) __sleep(),serialize序列化"name"和"id"
function __sleep() {
return (array ("name, id")); //do not serialize this->id 不串行化id
}
输出:
object(User)#1 (2) { ["name"]=> string(4) "HAHA" ["id"]=> string(13) "4f699a67954c4" } object(User)#2 (2) { ["name"]=> string(4) "HAHA" ["id"]=> string(13) "4f699a67954c4" }
4) __wakeup(), 反序列化"id"
<?php
class User {
public $name;
public $id;
function __construct() {
$this->id = uniqid (); //give user a unique ID 赋予一个不同的ID
}
function __sleep() {
return (array ("name" )); //do not serialize this->id 不串行化id
}
function __wakeup() {
$this->id = uniqid (); //give user a unique ID
}
}
$u = new User ();
$u->name = "HAHA";
$s = serialize ( $u ); //serialize it 串行化 注意不串行化id属性,id的值被抛弃
$u2 = unserialize ( $s ); //unserialize it 反串行化 id被重新赋值
//$u and $u2 have different IDs $u和$u2有不同的ID
var_dump ( $u );
var_dump ( $u2 );
?>
输出:
object(User)#1 (2) { ["name"]=> string(4) "HAHA" ["id"]=> string(13) "4f699ab00ae11" } object(User)#2 (2) { ["name"]=> string(4) "HAHA" ["id"]=> string(13) "4f699ab00aec8" }