類和對象
類是對一類事物的描述,對象是類的實例。在面向對象編程思想中一切事物都是對象,類和對象是面向對象編程的重要組成部分。
類的定義
class Person
{
public $name;
function eat(){
echo 'I am eating';
}
function self_introduce(){
echo 'my name is '.$this->name;
}
function get_this(){
if (isset($this)) {
echo 'class is '.get_class($this);
} else {
echo 'there is no $this';
}
}
}
class Book
{
function get_that(){
Person::get_this();
}
}
$tom = new Person();
$tom->name = 'tom';
$tom->eat(); // I am eating
echo '<br/>';
$tom->self_introduce(); // my name is tom
echo '<br/>';
$tom->get_this(); // class is Person
echo '<br/>';
Person::get_this();
// Deprecated: Non-static method Person::get_this() should not be called statically in D:\www\test\test1.php on line 39
// there is no $this
echo '<br/>';
$three_country = new Book;
$three_country->get_that();
// Deprecated: Non-static method Person::get_this() should not be called statically in D:\www\test\test1.php on line 26
// there is no $this
echo '<br/>';
Book::get_that();
// Deprecated: Non-static method Book::get_that() should not be called statically in D:\www\test\test1.php on line 50
// Deprecated: Non-static method Person::get_this() should not be called statically in D:\www\test\test1.php on line 26
// there is no $this
$class_name = 'Person';
$jack = new $class_name();
echo '<pre>';
print_r($jack);
echo '</pre>';
/*
Person Object
(
[name] =>
)
*/
$lucy = $jack;
$lily = &$jack;
$jack = null;
echo '<pre>';
var_dump($jack);
echo '</pre>';
echo '<pre>';
var_dump($lucy);
echo '</pre>';
echo '<pre>';
var_dump($lily);
echo '</pre>';
/*
NULL
object(Person)#1 (1) {
["name"]=>
NULL
}
NULL
*/
$jim = new Person();
$andy = new $jim;
echo '<pre>';
print_r($andy);
echo '</pre>';
echo '<pre>';
var_dump($jim == $andy);
echo '</pre>';
echo '<pre>';
var_dump($jim === $andy);
echo '</pre>';
$john = new Person();
echo '<pre>';
var_dump($jim == $john);
echo '</pre>';
echo '<pre>';
var_dump($jim === $john);
echo '</pre>';
/*
Person Object
(
[name] =>
)
bool(true)
bool(false)
bool(true)
bool(false)
*/
class Programmer extends Person
{
function self_introduce(){
parent::self_introduce();
echo '<br/>';
echo 'I am a programmer, my name is '.$this->name;
}
}
$hanks = new Programmer();
$hanks->name = 'hanks';
$hanks->self_introduce();
// my name is hanks
// I am a programmer, my name is hanks
- 類的定義以關鍵字
class
開頭,后面跟著類名,然后是一對大括號包圍的類結構。 - 一個合法的類名由字母數字和下劃線組成且不能以數字開頭。
- 類名通常用大駝峰法命名,花括號都獨占一行,這些不是必須的。
- 類結構中可以包含變量,常量和函數,在類中的變量是類的屬性,常量是類常量,函數是類的方法。
-
$this
是一個可以在類內部使用的偽變量,是一個到主叫對象的引用。 - 函數
get_class()
用來獲取指定對象所屬的類。 -
::
是范圍解析操作符,可以用于在類外訪問類的方法。 - 通過
new
關鍵字來實例化一個類成為對象。 -
->
是對象運算符,可以用來訪問對象的屬性和方法。 - 類名可以使用變量表示。
- 可以使用
extends
關鍵字指定一個類繼承自另一個類,繼承的類就有了被繼承類的屬性和方法。在php
中一個類只能繼承自一個基類。繼承的屬性和方法可以通過同名屬性和方法去覆蓋,父類中使用final
關鍵字聲明的方法不能覆蓋,可以使用parent::
來訪問父類中被覆蓋的屬性和方法。覆蓋父類方法時,除了構造函數,其它的方法的參數列表需要和父類保持一致。
類的屬性
類中的成員變量就是類的屬性。屬性的聲明要以關鍵字public
, protected
或private
開頭,后面跟著一個變量聲明,作為屬性的變量可以進行初始化,public
, protected
或private
表示了屬性的可見性。
$shanghai = 'shanghai';
const JIANGSU = 'jiangsu';
class Person
{
// $name; // Parse error: syntax error, unexpected '$name' (T_VARIABLE), expecting function (T_FUNCTION) or const (T_CONST) in
var $name;
public $sex;
public $age = 12;
public $count = 1 + 2;
public $introduction = 'I am a '.'programmer';
public $motto = <<<EOD
impossible is nothing
EOD;
// public $hello = self::return_string(); // Fatal error: Constant expression contains invalid operations in
// public $city = $shanghai; // Fatal error: Constant expression contains invalid operations in
public static $new_name = 'another name';
// public $another_name = self::$new_name; // Fatal error: Constant expression contains invalid operations
public $province = JIANGSU;
public $area = ['putuo', 'minhang'];
public $mobile = <<<'EOD'
11111111111
EOD;
static function return_string(){
return 'hello';
}
function return_hello(){
return self::return_string();
}
function return_shanghai(){
return $shanghai;
}
function return_new_name(){
return self::$new_name;
}
}
$tom = new Person();
echo '<pre>';
var_dump($tom->name); // NULL
echo '</pre>';
echo '<pre>';
var_dump($tom->sex); // NULL
echo '</pre>';
echo $tom->age; // 12
echo '<br/>';
echo $tom->introduction; // I am a programmer
echo '<br/>';
echo $tom->motto; // impossible is nothing
echo '<br/>';
echo Person::return_string(); // hello
echo '<br/>';
echo $tom->return_hello(); // hello
echo '<br/>';
echo $tom->return_shanghai(); // Notice: Undefined variable: shanghai in
echo '<br/>';
echo $tom->return_new_name(); // another name
echo '<br/>';
echo $tom->count; // 3
echo '<br/>';
echo JIANGSU; // jiangsu
echo '<br/>';
echo $tom->province; // jiangsu
echo '<br/>';
echo ANHUI;
// Notice: Use of undefined constant ANHUI - assumed 'ANHUI' in
// ANHUI
echo '<br/>';
echo '<pre>';
print_r($tom->area);
echo '</pre>';
/*
Array
(
[0] => putuo
[1] => minhang
)
*/
echo '<br/>';
echo $tom->mobile; // 11111111111
- 可以通過對象運算符
->
訪問非靜態屬性,靜態屬性要通過::
來訪問。 - 可以通過關鍵字
var
來聲明屬性,這是php5
之前用法,在php5
的某些版本這種用法被廢棄并會產生報錯,如果沒有使用public
,protected
或private
等修飾符,僅使用var
聲明的變量會被認為是public
的。 - 類中的關鍵字
self
表示類本身。
類常量
在類中定義的常量被稱為類常量。
$count = 2;
class Person
{
const head_number = 1;
// define(eyes_number, 2); // Parse error: syntax error, unexpected 'define' (T_STRING), expecting function (T_FUNCTION) or const (T_CONST) in
const EYES_NUMBER = 2;
// const 1hands_number = 1; // Parse error: syntax error, unexpected '1' (T_LNUMBER) in
const _handsnumber2 = 2;
// const hands_@number = 3; // Parse error: syntax error, unexpected '@', expecting '=' in
// const hands_number; // Parse error: syntax error, unexpected ';', expecting '=' in
const hands_number = 1 + 1;
public static $count = 2;
// const legs_number = $count; // Fatal error: Constant expression contains invalid operations in
// const legs_number = self::$count; // Fatal error: Constant expression contains invalid operations in
// const legs_number = self::return_count(); // Fatal error: Constant expression contains invalid operations in
const hello = <<<EOD
hello
EOD;
const world = <<<'EOD'
world
EOD;
const arr = [0, 1, 2];
static function return_count(){
return self::$count;
}
function return_head_number(){
return self::head_number;
}
}
echo Person::head_number; // 1
echo '<br/>';
// echo Person::eyes_number; // Fatal error: Uncaught Error: Undefined class constant 'eyes_number' in
// echo Person::eyes_number; // Fatal error: Uncaught Error: Undefined class constant 'eyes_number' in
echo Person::EYES_NUMBER; // 2
echo '<br/>';
echo Person::_handsnumber2; // 2
echo '<br/>';
echo Person::hands_number; // 2
echo '<br/>';
$tom = new Person;
echo $tom->return_head_number(); // 1
$class_name = 'Person';
echo '<br/>';
echo $class_name::head_number; // 1
echo '<br/>';
echo $tom::head_number; // 1
echo '<br/>';
// echo $tom->head_number; // Notice: Undefined property: Person::$head_number in
echo $tom::hello; // hello
echo '<br/>';
echo $tom::world; // world
echo '<br/>';
echo '<pre>';
print_r($tom::arr);
echo '</pre>';
/*
Array
(
[0] => 0
[1] => 1
[2] => 2
)
*/
- 類常量必須是一個定值,不能是變量,類屬性或是函數調用結果。
- 可以通過
const
關鍵字來定義類常量但是不可以使用define()
函數。 - 類常量不用
$
符作為前引,類常量名由數字字母下劃線構成但是不能以數字開頭,類常量名區分大小寫。 - 常量聲明時就要初始化值。
- 在類外部訪問常量可以聽過類或者對象使用
::
運算符來進行,在類內部訪問使用常量可以通過self::
來進行,self
表示類本身。
類的繼承
繼承是面向對象編程時實現代碼復用的重要途徑,繼承會影響到類與類,對象與對象之間的關系。通過繼承可以讓一個類擁有和擴展另一個類的功能,前者被稱為子類,后者被稱為父類或基類。
class Person
{
public $name = 'stone';
protected $sex;
private $age;
public function return_name(){
return $this->name;
}
protected function set_name($name){
$this->name = $name;
}
private function return_class_name(){
return 'Person';
}
public function return_string(){
return 'hello';
}
}
$tom = new Person;
echo '<pre>';
print_r($tom);
echo '</pre>';
/*
Person Object
(
[name] => stone
[sex:protected] =>
[age:Person:private] =>
)
*/
$tom->name = 'tom';
echo $tom->return_name(); // tom
echo '<br/>';
echo $tom->return_string(); // hello
class Programmer extends Person
{
function return_string(){
return 'world';
}
}
$stone = new Programmer;
echo '<pre>';
print_r($stone);
echo '</pre>';
/*
Programmer Object
(
[name] => stone
[sex:protected] =>
[age:Person:private] =>
)
*/
var_dump($stone->introduction);
// Notice: Undefined property: Programmer::$introduction in
// NULL
echo '<br/>';
$stone->introduction = 'I am a programmer';
echo $stone->introduction; // I am a programmer
echo '<br/>';
var_dump($stone->name); // string(5) "stone"
echo '<br/>';
echo $stone->return_name(); // stone
echo '<br/>';
echo $stone->return_string(); // world
- 子類會繼承父類所有公有和受保護的方法,子類可以通過重寫來覆蓋父類的方法。
- 父類必須在子類之前被聲明。
- 繼承需要使用關鍵字
extends
。 - 父類的屬性也會被子類繼承。
構造函數和析構函數
構造函數用于在實例化一個類為對象時做一些初始化的操作,構造函數是類中一個在新建對象時會被自動調用的方法。析構函數在對象所有引用被刪除或對象被顯示銷毀時會被調用,析構函數適合做一些清理和收尾工作。
class Person
{
function __construct(){
echo 'this is a construct';
}
function __destruct(){
echo 'this is a destruct';
echo '<br/>';
}
}
$tom = new Person; // this is a construct
class Programmer extends Person
{
function __construct(){
parent::__construct();
echo '<br/>';
echo 'this is a programmer construct';
}
function __destruct(){
parent::__destruct();
echo 'this is a programmer destruct';
echo '<br/>';
}
}
echo '<br/>';
$stone = new Programmer;
/*
this is a construct
this is a programmer construct
*/
class Saler extends Person
{
}
echo '<br/>';
$jim = new Saler; // this is a construct
class Animal
{
public $name;
function __construct($name){
$this->name = $name;
}
function get_name(){
return $this->name;
}
function __destruct(){
$this->name = null;
echo 'this is an Animal destruct';
echo '<br/>';
}
}
$nick = new Animal('nick');
echo '<br/>';
echo $nick->get_name(); // nick
echo '<br/>';
/*
this is an Animal destruct
this is a destruct
this is a destruct
this is a programmer destruct
this is a destruct
*/
- 構造函數的名稱為
__construct
。 - 析構函數的名稱為
__destruct
。 - 子類可以繼承父類的非
private
構造函數,在子類覆蓋了父類的構造函數時如果要調用父類的構造函數可以通過使用parent::__construct
來進行。 - 構造函數可以有參數,析構函數不可以有參數,構造函數和析構函數都不能有返回值。
- 子類可以繼承父類的非
private
析造函數,在子類覆蓋了父類的析造函數時如果要調用父類的析造函數可以通過使用parent::__destruct
來進行。
訪問控制
通過訪問控制可以指定類的成員(包括屬性和方法)的訪問范圍,可以通過在類成員前面加上修飾符public
, protected
或private
來指定訪問控制。
class Person
{
var $name = 'tom';
protected $sex = 'male';
private $age = 30;
public $introduction = 'I am a person';
function echo_info(){
echo $this->name;
echo '<br/>';
echo $this->sex;
echo '<br/>';
echo $this->age;
echo '<br/>';
echo $this->introduction;
}
function a_public_function(){
echo 'this is a public function in Person';
echo '<br/>';
}
protected function a_protected_function(){
echo 'this is a protected function in Person';
echo '<br/>';
}
private function a_private_function(){
echo 'this is a private function in Person';
echo '<br/>';
}
public function show_function(){
$this->a_public_function();
$this->a_protected_function();
$this->a_private_function();
}
}
$tom = new Person();
echo '<pre>';
print_r($tom);
echo '</pre>';
/*
Person Object
(
[name] => tom
[sex:protected] => male
[age:Person:private] => 30
[introduction] => I am a person
)
*/
$tom->echo_info();
/*
tom
male
30
I am a person
*/
echo '<br/>';
echo $tom->name; // tom
echo '<br/>';
// echo $tom->sex; // Fatal error: Uncaught Error: Cannot access protected property Person::$sex in
echo '<br/>';
// echo $tom->age; // Fatal error: Uncaught Error: Cannot access private property Person::$age in
echo '<br/>';
echo $tom->introduction; // I am a person
echo '<br/>';
$tom->a_public_function(); // this is a public function in Person
// $tom->a_protected_function(); // Fatal error: Uncaught Error: Call to protected method Person::a_protected_function() from context '' in
// $tom->a_private_function(); // Fatal error: Uncaught Error: Call to private method Person::a_private_function() from context '' in
$tom->show_function();
/*
this is a public function in Person
this is a protected function in Person
this is a private function in Person
*/
class Programmer extends Person
{
public $name = 'stone';
function echo_info(){
echo $this->name;
echo '<br/>';
echo $this->sex;
echo '<br/>';
echo $this->age;
echo '<br/>';
echo $this->introduction;
echo '<br/>';
}
public function programmer_show_function(){
$this->a_public_function();
$this->a_protected_function();
// $this->a_private_function(); // Fatal error: Uncaught Error: Call to private method Person::a_private_function() from context 'Programmer' in
}
}
$stone = new Programmer;
echo '<pre>';
print_r($stone);
echo '</pre>';
/*
Programmer Object
(
[name] => stone
[sex:protected] => male
[age:Person:private] => 30
[introduction] => I am a person
)
*/
echo $stone->name; // stone
echo '<br/>';
// echo $stone->sex; // Fatal error: Uncaught Error: Cannot access protected property Programmer::$sex in
echo '<br/>';
echo $stone->age; // Notice: Undefined property: Programmer::$age in
echo '<br/>';
$stone->echo_info();
/*
stone
male
Notice: Undefined property: Programmer::$age in D:\www\test\test1.php on line 59
I am a person
*/
$stone->a_public_function(); // this is a public function in Person
// $stone->a_protected_function(); // Fatal error: Uncaught Error: Call to protected method Person::a_protected_function() from context '' in
// $stone->a_private_function(); // Fatal error: Uncaught Error: Call to private method Person::a_private_function() from context '' in
$stone->show_function();
/*
this is a public function in Person
this is a protected function in Person
this is a private function in Person
*/
$stone->programmer_show_function();
/*
this is a public function in Person
this is a protected function in Person
*/
class Saler extends Person
{
function a_public_function(){
echo 'this is a public function in Saler';
echo '<br/>';
}
protected function a_protected_function(){
echo 'this is a protected function in Saler';
echo '<br/>';
}
private function a_private_function(){
echo 'this is a private fucntion in Saler';
echo '<br/>';
}
public function saler_show_function(){
$this->a_public_function();
$this->a_protected_function();
$this->a_private_function();
}
}
$jim = new Saler;
$jim->a_public_function(); // this is a public function in Saler
// $jim->a_protected_function(); // Fatal error: Uncaught Error: Call to protected method Saler::a_protected_function() from context '' in
// $jim->a_private_function(); // Fatal error: Uncaught Error: Call to private method Saler::a_private_function() from context '' in
$jim->show_function();
/*
this is a public function in Saler
this is a protected function in Saler
this is a private function in Person
*/
$jim->saler_show_function();
/*
this is a public function in Saler
this is a protected function in Saler
this is a private fucntion in Saler
*/
class Animal
{
private $name;
function __construct($name){
$this->name = $name;
}
private function echo_name(){
echo 'my name is '.$this->name;
echo '<br/>';
}
function access_private(Animal $animal){
// $animal->name = 'tom';
$animal->echo_name();
}
}
$jack = new Animal('jack');
// $jack->echo_name(); // Fatal error: Uncaught Error: Call to private method Animal::echo_name() from context '' in
// echo $jack->name; // Fatal error: Uncaught Error: Cannot access private property Animal::$name in
$jack->access_private(new Animal('lucy')); // my name is lucy
- 被
public
修飾的類成員是公有的,可以在任何地方被訪問。 - 被
protected
修飾的類成員是受保護的,可以被類本身,子類和父類訪問。 - 被
private
修飾的類成員是私有的,只能被類本身訪問。 - 沒有被訪問控制關鍵字修飾的類成員被認為是公有的,即
public
。 - 子類會繼承父類的公有和受保護的類成員,可以重寫這些這些類成員。
- 若想訪問其它對象的私有或受保護的屬性和方法則可以通過將對象作為參數傳遞給另一個對象的方法來實現。
類的自動加載
通過類的自動加載可以避免冗長的文件加載列表,在php
中可以使用函數spl_autoload_register()
來完成類的自動加載。
// Person.php
class Person
{
public $name;
function say_something(){
echo 'I say something';
echo '<br/>';
}
}
// Programmer.php
class Programmer extends Person
{
public $name;
function coding(){
echo 'I am coding...';
echo '<br/>';
}
}
// Animal.php
class Animal
{
public $name;
function eat(){
echo 'I am eating';
}
}
// index.php
/*require_once('./Person.php');
require_once('./Programmer.php');
require_once('./Animal.php');*/
spl_autoload_register(function($class_name){
require_once $class_name.'.php';
});
$tom = new Person();
$tom->say_something(); // I say something
$stone = new Programmer();
$stone->say_something(); // I say something
$stone->coding(); // I am coding...
$jack = new Animal;
$jack->eat(); // I am eating
范圍解析操作符
在php
中,由兩個冒號組成的運算符::
被稱為范圍解析操作符,通過::
可以訪問類的靜態成員和類常量,還可以通過范圍解析操作符來覆蓋類的屬性和方法。
class Person
{
// const CONST_VAR; // Parse error: syntax error, unexpected ';', expecting '=' in
const CONST_VAR = 'A CONST VARIABLE';
static function return_const(){
// return $this->CONST_VAR; // Fatal error: Uncaught Error: Using $this when not in object context in
return self::CONST_VAR;
}
protected function a_function(){
echo self::return_const();
echo '<br/>';
echo 'this is a protected funtion in Person';
echo '<br/>';
}
}
echo Person::CONST_VAR; // A CONST VARIABLE
echo '<br/>';
// echo Person::return_const(); // Fatal error: Uncaught Error: Using $this when not in object context in
$tom = new Person;
// echo $tom->return_const(); // Fatal error: Uncaught Error: Using $this when not in object context in
echo Person::return_const(); // A CONST VARIABLE
echo '<br/>';
$class_person = 'Person';
echo $class_person::CONST_VAR; // A CONST VARIABLE
echo '<br/>';
echo $class_person::return_const(); // A CONST VARIABLE
echo '<br/>';
class Programmer extends Person
{
public static $static_var = 'a static variable';
public static function echo_const_static(){
// echo self::CONST_VAR; // A CONST VARIABLE
echo parent::CONST_VAR;
echo '<br/>';
echo self::$static_var;
echo '<br/>';
}
function a_function(){
parent::a_function();
echo 'this is a function in Programmer';
echo '<br/>';
}
}
$stone = new Programmer;
// echo $stone->static_var;
// Notice: Accessing static property Programmer::$static_var as non static in
// Notice: Undefined property: Programmer::$static_var in
$stone->echo_const_static();
// A CONST VARIABLE
// a static variable
echo Programmer::$static_var;
echo '<br/>'; // a static variable
Programmer::echo_const_static();
/*
A CONST VARIABLE
a static variable
*/
$class_programmer = 'Programmer';
echo $class_programmer::$static_var; // a static variable
echo '<br/>';
$stone->a_function();
/*
A CONST VARIABLE
this is a protected funtion in Person
this is a function in Programmer
*/
- 可以通過變量來引用類,但是變量的值不能是
self
,parent
或static
。 - 通過
::
運算符可在類內部訪問類的本身的常量和靜態方法,可以訪問父類的類常量和方法。
本文首發于公眾號:programmer_cc,轉載請注明出處。
微信公眾號.jpg