php 常用的知识点归集(下)
24、靜態屬性與靜態方法在類中的使用
?需求:在玩CS的時候不停有伙伴加入,那么現在想知道共有多少人在玩,這個時候就可能用靜態變量的方法來處理
利用原有的全局變量的方法來解決以上的問題
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);$total = 0;class Game {public $name;public function __construct($name){$this->name = $name;}public function joinGame(){global $total;echo "{$this->name}小朋友加入了游戲...<br/>";$total++;} }$child1 = new Game('小明'); $child2 = new Game('小紅'); $child3 = new Game('小剛'); $child1->joinGame(); $child2->joinGame(); $child3->joinGame(); echo "現在有{$total}個小朋友在玩游戲"; /*** 輸出以下內容* 小明小朋友加入了游戲...* 小紅小朋友加入了游戲...* 小剛小朋友加入了游戲...* 現在有3個小朋友在玩游戲*/ ?>?靜態變量是類的靜態屬性,可以被所有對象共享,利用靜態變量的方法來解決以上的問題
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);class Game {public $name;public static $total = 0;public function __construct($name){$this->name = $name;}private function joinGame(){echo "{$this->name}加入到了游戲中...<br>";self::$total++;}public function getPersonNum(){echo "現在總共有" . self::$total . "個人加入到游戲中";}public function __call($class_name, $params){if (method_exists($this, $class_name)) {return call_user_func_array([$this, $class_name], $params);}return '沒有這種方法';} }$p1 = new Game('小明'); $p2 = new Game('小紅'); $p3 = new Game('小剛');$p1->joinGame(); $p2->joinGame(); $p3->joinGame();$p1->getPersonNum(); ?>?如何訪問靜態變量歸集
靜態變量在類里面的兩種表示方法1、self::$靜態變量名? 2、類名::$靜態變量名(::表示范圍解析符),如上面的可能表示為:self::$total或者Game::$total這兩種方式
在類的外部訪問靜態變量,可以使用:類名::$靜態變量名,但是前提是這個靜態屬性必需是公開的(public)
self與$this的區別 self是類的范疇(指向類),而$this是對象的實例(指向類的實例)
靜態方法
如果程序員在類中需要對靜態屬性進行操作,那么可以定義靜態方法進行操作,換言之靜態方法主要是操作靜態屬性的
在類的外部訪問靜態方法有三種方式如下例子
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);class Person {public $name;public static $address = '中國';public function __construct($name){$this->name = $name;}public static function getAddress(){return self::$address;} } //建議使用第一種方式,不建議使用第二種第三種方式 //方式一 echo Person::getAddress(); //輸出 中國 //方式二 $p = new Person('小明'); echo $p::getAddress(); //輸出 中國 //方式三 echo '<br>'; echo $p->getAddress(); //輸出 中國 ?>?在類的內部訪問類的靜態方法的三種方式
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);class Person {public $name;public static $address = '中國';public function __construct($name){$this->name = $name;}public static function getAddress(){return self::$address;}public function getStaticMethod(){//方式一echo self::getAddress();echo '<br>';//方式二echo Person::getAddress();echo '<br>';//方式三echo $this->getAddress();} }$p = new Person('leo'); $p->getStaticMethod(); //輸出 中國 中國 中國 ?>?25、利用靜態變量或者靜態方法來實現單例模式(注意這里還沒有規避來自繼承的風險)
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);class Person {public $name;public $age;static $pe;/**把構造函數設置為私有的方法,以便更好的進行單例模式* Person constructor.* @param $name* @param $age*/private function __construct($name, $age){$this->name = $name;$this->age = $age;}//阻止克隆private function __clone(){}// /**第一種寫法利用靜態方法來實例化類 // * @param $name // * @param $age // * @return Person // */ // static function getPerson($name, $age) // { // if (!self::$pe) { // self::$pe = new Person($name, $age); // } // return self::$pe; // }/**第二種寫法利用靜態方法來實例化類(常用的方法)* @param $name* @param $age* @return Person*/static function getPerson($name, $age){if (!self::$pe instanceof self) {self::$pe = new self($name, $age);}return self::$pe;} }$p1 = Person::getPerson('小明', 30); $p2 = Person::getPerson('小紅', 30); $p3 = Person::getPerson('小剛', 30); var_dump($p1, $p2, $p3); //輸出三個對象,都是一個變量 object(Person)#1 (2) { ["name"]=> string(6) "小明" ["age"]=> int(30) } object(Person)#1 (2) { ["name"]=> string(6) "小明" ["age"]=> int(30) } object(Person)#1 (2) { ["name"]=> string(6) "小明" ["age"]=> int(30) } ?>?26、oop編程的三大特征
oop編程的三大特征:封裝性,繼承,多態,說明一下,在Php的面向對象編程中,多態提及的不多,因為Php天生就是多態的語言
?封裝性細節普通屬性要定義成public,protected,private三者之一,否則會報錯,如果用var(php4添加的定義方法)定義,則視為Public,靜態屬性可以不寫這個修辭符,但是默認為public。
封裝性的重點---對象連用祥見以下例子
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);class Student {public $name;private $class_name;public function __construct($name, $class){$this->name = $name;$this->class_name = $class;}/**獲取班級的函數* @return mixed*/public function getClass(){return $this->class_name;}/**設置班級的函數* @param $new_class*/public function setClass($new_class){$this->class_name = $new_class;} }class ClassName {public $name;private $school_name;public function __construct($name, $school){$this->name = $name;$this->school_name = $school;}/**獲取學校的函數* @return mixed*/public function getSchool(){return $this->school_name;}/**設置學校的函數* @param $new_school*/public function setSchool($new_school){$this->school_name = $new_school;} }class School {public $name;public function __construct($name){$this->name = $name;} }$school = new School('精英學院'); //把school這個對象作為一個參數傳入函數 $className = new ClassName('精英一班', $school); //把班級這個對象作為一個參數傳入函數 $stu = new Student('Leo', $className); //注意這種連續調用的情況 var_dump($stu->getClass()->getSchool()); ?>?oop編程的繼承
為了解決代碼的冗余,實現代碼的復用,oop編程可以實現繼承(基類,擴展類=》父類,子類)用關鍵字extends來實現繼承
注意:如果在子類里覆蓋了父類的方法那么要用關鍵字parent::方法名(調用的是類里面的方法,而不是實例化后的方法)或者用父類名::方法名來調用(可以是靜態方法,也可以是普通方法),但是如果子類里面沒有覆蓋父類里面的方法,那么可能用$this->方法名來調用;parent::屬性名可以訪問父類的靜態屬性,但是不能訪問父類里的屬性因為那個是要實例化后才有的屬性祥見例子
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);class Student {public $name;public $classNum;protected $score;protected $isTest;public function __construct($name, $classNum){$this->name = $name;$this->classNum = $classNum;}public function testing(){echo '現在正在測試...';$this->isTest = true;$this->score = mt_rand(10, 100);}public function getScore(){return $this->score;} }class PrimaryStudent extends Student {public $addFood;public function __construct($name, $className, $food){ parent::__construct($name, $className);$this->addFood = $food;}public function getAll(){return ['score' => parent::getScore(),'food' => $this->addFood];} }$p = new PrimaryStudent('leo', 20, 'brake'); $p->testing(); echo '<br/>'; var_dump($p->getAll()); //輸出 現在正在測試... //array(2) { ["score"]=> int(52) ["food"]=> string(5) "brake" } ?>?子類對父類方法的重寫,屬性保證方法名和參數是一致的,否則會報錯,如果參數添加了類型約束,那么,子類的類型約束必需和父類是一致的,否則也是會報錯的
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);class Person {public $name;public function __construct($name){$this->name = $name;}public function sayHello(string $str){echo 'hello' . $str;} }class Student extends Person {//重寫方法的時候,函數名和參數必需和父類的一致,否則會報錯public function sayHello(string $str){echo 'are you ok???' . $str;} }$p = new Student('leo'); $p->sayHello('haha'); //輸出 are you ok???haha ?>?子類對父類進行重寫的時候,函數的修飾符可以放大,但是不能縮小,比如protected可以變成public但是不能變成private,并且在子類調用父類的方法中,子類繼承了父類的屬性,那么會輸出子類的屬性值,當子類沒有調用父類的屬性時,那么會輸出父類的值
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);class A {public $num1 = 999;protected $num2;private $num3 = 888;public function __construct(int $num){$this->num2 = $num;}public function showNum1(){return $this->num1;}public function showNum2(){return $this->num2;}public function showNum3(){return $this->num3;}public function setNum3(){$this->num3 = 888666;} }class B extends A {public $num1 = 333;public $num2 = 666;public $num3 = 777; }class C extends A { }$t = new B(111); $f = new C(789); echo $t->showNum1() . '<br>'; //輸出 333 echo $t->showNum2() . '<br>'; //輸出 111 $f->setNum3(); //改變的是自己繼承的父類,不會改變其他類的父類 echo $t->showNum3() . '<br>'; //輸出 888 子類沒有繼承父類的屬性,輸出的是父類的屬性值 echo $f->showNum3(); //輸出 888666 子類沒有繼承父類的屬性,輸出的是父類的屬性值 ?>?27、抽象類
抽象類的存在的價值是,讓其他類來繼承他,并實現它寫的抽象方法,它的價值在于設計
抽象類的6個細節
1、抽象類不能被實例化,如果里面的靜態方法不是抽象的,那么是可以調用靜態方法的
2、抽象類可以沒有抽象方法
3、抽象類中可以有普通的成員方法,屬性和常量
4、如果一個類中有了抽象方法,則這個類必需聲明為abstract
5、抽象方法不能有方法體,即不能有{}
6、如果一個類,繼承了某個抽象類,則該類,必須把這個抽象類所有的抽象方法全部實現(除非,該類自已也聲明為abstract類);并且實現的過程中,如果基類里的抽象方法里有形參,那么繼承的方法里面也需要有形參,不能省略。
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);/**抽象類,實現兩個方法* Class Person*/ abstract class Person {public $name;public $age;abstract public function cry();abstract public function run(); }class student extends Person{public function __construct($name, $age) {$this->name = $name;$this->age = $age;}public function cry() {return "my name is {$this->name}";}public function run() {return "I can run";} }$student1 = new student('leo', 30); var_dump($student1); //輸出 object(student)#1 (2) { ["name"]=> string(3) "leo" ["age"]=> int(30) } echo $student1->cry(); //輸出 my name is leo echo $student1->run(); //輸出 I can run ?>?28、接口
接口的細節:注意接口的命名規則是第一個字母小寫,一般以i開頭,其他的按照駝峰命名規則進行命名
1、接口不能實例化
2、接口中的所有方法,都不能實現,即不能有方法體
3、一個類可以實現多個接口,并且需要把所有接口的方法都實現
4、一個接口中,可以有屬性,但是必需是常量,并且這個常量的訪問方法與靜態變量的方法一樣
5、接口中的所有方法都是Public,默認即Public;
6、一個接口可以繼承其他接口,可以多繼承,中間用逗號隔開,但是接口是不能繼承類的(注意:php是繼承的,即一個類只能有一個父類,不能有多個父類,但接口就不一樣了);
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);/**人類的接口* Interface Person*/ interface Person{const STATUS = true;public function run();public function cry(); }/**動物的接口* Interface Animal*/ interface Animal {public function eating(); }/**實現人類的接口與動物的接口* Class Student*/ class Student implements Person, Animal {public $name;public $age;public function __construct($name, $age){$this->name = $name;$this->age = $age;}public function run() {echo "{$this->name} can run<br>";}public function cry() {echo "he is {$this->age} year old, but also cry <br/>";}public function eating() {echo "{$this->name} can eating";} }class Ask {public $person;public function __construct(Student $st){$this->person = $st;}public function init() {$this->person->cry();$this->person->run();$this->person->eating();} }$s=new Student('leo',3); $t=new Ask($s); $t->init(); /*** 輸出* he is 3 year old, but also cry* leo can run* leo can eating*/ ?>?29、關鍵字 final在類中的使用
?A、當程序員不希望某個成員方法被子類重寫時,我們可以將該方法修飾為final方法。
?B、當程序員不希望某個類被繼承,我們可以將該類修飾為final類
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);final class A {public $name;public $age;public function __construct($name, $age) {$this->name = $name;$this->age = $age;} }class B extends A {} //會報錯,因為final類是不允許被繼承的class A {public $name;public $age;public function __construct($name, $age) {$this->name = $name;$this->age = $age;}final public function init() {echo "my name is {$this->name} I'm {$this->age} year old";} }class B extends A {public function init() {echo 'are you ok???';} } //會報錯,因為有final修飾的方法是不能被重寫的 ?>?final關鍵字的使用細節說明
a、final 不能夠修飾成員屬性(變量);
b、final 方法不能被重寫,但可以被繼承;
c、一般來說,final類中不會出現final方法,因為final類都不能被繼承,也就不會去重寫final方法
d、final類是可以被實例化的
?30、類常量
類中的常量的定義示例
class 類名 {
const 常量名 = 常量值
}
常量的命名規范:全部大寫,并且用下劃線隔開
常量不能是對象,也不能是資源,其他類型的可以
常量的訪問參考靜態變量的訪問
?31、類的其他知識點的學習
a、類的遍歷 ,在類的外部對類進行遍歷,那么可以遍歷到所有public修飾的屬性值,但是在類的內部對類進行遍歷,那么可以遍歷所有的屬性值(不含方法)即Public,protected,private三種屬性值
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);class A {public $name;public $age;protected $sex;private $salary;public function __construct($name, $age, $sex, $salary){$this->name = $name;$this->age = $age;$this->sex = $sex;$this->salary = $salary;}public function count(){foreach ($this as $key => $val) {echo "{$key} => {$val}<br/>";}} }$a = new A('leo', 33, 'man', 20000); foreach ($a as $key => $val) {echo "{$key} => {$val}<br/>"; } //輸出 //name => leo //age => 33 $a->count(); //輸出 //name => leo //age => 33 //sex => man //salary => 20000 ?>?b、內置標準類
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);$a = new stdClass(); var_dump($a); //輸出 object(stdClass)#1 (0) { } //如果有這個需求,那么可以往里面填充數據 $a->name = 'are you ok???'; $a->age = 24; var_dump($a); //輸出 object(stdClass)#1 (2) { ["name"]=> string(13) "are you ok???" ["age"]=> int(24) } ?>?c、類與數組或者其他形式的值進行互相轉換
當類轉成數組時,私有的變量仍然不能訪問
數組或者其他形式的變量轉成類時,會轉成標準類
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);$array = ['name' => 'aaa','age' => 30,'say' => function () {echo 'are you ok???';} ]; var_dump($array); echo '<br>'; //輸出 array(3) { ["name"]=> string(3) "aaa" ["age"]=> int(30) ["say"]=> object(Closure)#1 (0) { } } $array['say'](); //輸出 are you ok??? $obj=(object) $array; echo '<br>'; var_dump($obj); //輸出 object(stdClass)#2 (3) { ["name"]=> string(3) "aaa" ["age"]=> int(30) ["say"]=> object(Closure)#1 (0) { } } ?>?d、類的序列化與類的反序列化
如果需要把實例化后的類存儲起來,那么可以把類序列化成字符串進行存儲(要用到關鍵函數 serialize);
當需要把序列化好的類進行返序列化使用那么可以進行反序列化(要用關鍵函數 unserialize);
注意在使用反序列化好的類時,要把原有的類的方法引入到當前文件,直接用require_once或者include_once即可
?魔術方法__sleep和__wakeup
__sleep 方法定義在需要被系列化的類里,并且本方法返回的是一個數組,該數組是指定哪些變量需要被序列化,靜態變量不能被指定,是給程序員一個機會在序列化前改變一些變量
__wakeup方法也是定義在需要被系列化的類里,是給程序員一個機會在反序列化前改變一些變量?
定義類的文件
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);class A {public $name;public $age;static $salary;public function __construct($name, $age, $salary){$this->name = $name;$this->age = $age;self::$salary = $salary;}public function introduce(){echo "hello , my name is {$this->name},I'm {$this->age} years old";}public function __sleep(){//改變序列化前name的值為aaa$this->name = 'aaa';//指定兩個變量需要被序列化,返回值一定要是一個數組return ['name', 'age'];}public function __wakeup(){//改變返序列化前age的值為40;$this->age = 40;} }$a = new A('leo', 30, 10000); //進行序列化 $_a = serialize($a); //把序列化后的字符串寫入文件 file_put_contents('./yftest.txt', $_a); ?>引用類的文件
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); //注意一定要引入原本的類,否則無法引用已經實例化后的數據; require_once './index.php'; $str = file_get_contents('./yftest.txt'); //進行反序列化操作 $a = unserialize($str); var_dump($a); //輸出 object(A)#2 (2) { ["name"]=> string(3) "aaa" ["age"]=> int(40) } var_dump($a::$salary); //輸出 10000; $a->introduce(); //輸出 hello , my name is aaa,I'm 40 years old ?>?E、traits的講解(重點)
如果有個些類根據定制按需要決定是否擁有指定的方法,那么不能用繼承,這個時候就需要用到traits技術了
使用時用關鍵字use 類名(traits類名);
注意:
1、默認時traits里的修飾是Public,如果是private 或者是 protected,那么就沒有辦法引用。
2、如果trait里面的方法與類的父類的名字重合,相當于對類的方法的重寫,那么就必需遵循類重寫的規則(規定的參數和類型必需一致)。
3、trait類里可以使用類里的方法及靜態方法,及變量,靜態變量,類里同時也可以訪問以上的變量和方法。
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);class A {public $name;public $age;public function __construct($name, $age){$this->name = $name;$this->age = $age;}public function introduce(){echo "this is A's method";} }trait Common {static $ask = 'are you ok???';public function introduce(){echo "你好啊,我的名字啊{$this->name},我今年{$this->age}歲了<br/>";//輸出 你好啊,我的名字啊leo,我今年28歲了var_dump($this);//輸出 object(B)#1 (2) { ["name"]=> string(3) "leo" ["age"]=> int(28) }echo self::$cry;//輸出 wwwecho self::$ask;//輸出 are you ok??? } }class B extends A {use Common; //引用trait類static $cry = 'www';public function test(){echo self::$ask;} }class C extends A {}$b = new B('leo', 28); //C類里沒有引用,所以C的實例沒有那個方法 $c = new C('john', 50); $b->introduce(); $b->test(); //輸出 are you ok??? ?>?F、反射類
所以的類都是一個對象,可能通過建立反射類來返回所有類的信息
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);class A {public $name;public $age;public function __construct($name, $age){$this->name = $name;$this->age = $age;}public function __toString(){$ref = new ReflectionClass($this);echo $ref->getName(), '<br/>';//輸出 Avar_dump($ref->getMethods()); //獲取所有的方法//輸出 array(2) { [0]=> object(ReflectionMethod)#3 (2) { ["name"]=> string(11) "__construct" ["class"]=> string(1) "A" } [1]=> object(ReflectionMethod)#4 (2) { ["name"]=> string(10) "__toString" ["class"]=> string(1) "A" } }var_dump($ref->getProperties()); //獲取所有的屬性//輸出 array(2) { [0]=> object(ReflectionProperty)#4 (2) { ["name"]=> string(4) "name" ["class"]=> string(1) "A" } [1]=> object(ReflectionProperty)#3 (2) { ["name"]=> string(3) "age" ["class"]=> string(1) "A" } }return '';} }$a = new A('LEO', 23); echo $a; ?>?通過反射機制來實例化類,并且調用方法
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);class A {public $name;public $age;public function __construct($name, $age){$this->name = $name;$this->age = $age;}public function sayHello($name){echo "hello {$name}, my name is {$this->name} I'm {$this->age} years old";} }//創建反射機制對象 $reflect_obj = new ReflectionClass('A'); //通過反射機制創建實例 $reflect_instance = $reflect_obj->newInstance('leo', 30); //得到返射方法,這個時候框架就可以通過這個對象做中間處理,比如判斷是否是公有的,私有的等等 $reflect_method_sayHello = $reflect_obj->getMethod('sayHello'); //進行返射調用該方法 $reflect_method_sayHello->invoke($reflect_instance, 'jim');?>?模擬TP的控制器原理
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true);class IndexAction {public function Index(){echo 'this is index method<br/>';}public function beforeIndex(){echo 'this is beforeIndex method<br/>';}public function afterIndex(){echo 'this is afterIndex method<br/>';}public function test(){echo 'this is test method<br/>';} }if (class_exists('IndexAction')) {$reflect_obj = new ReflectionClass('IndexAction');$reflect_instance = $reflect_obj->newInstance();if ($reflect_obj->hasMethod('Index')) {$reflect_obj_index = $reflect_obj->getMethod('Index');if ($reflect_obj_index->isPublic()) {if ($reflect_obj->hasMethod('beforeIndex')) {$reflect_obj_before_index = $reflect_obj->getMethod('beforeIndex');$reflect_obj_before_index->isPublic() && $reflect_obj_before_index->invoke($reflect_instance);}$reflect_obj_index->invoke($reflect_instance);if ($reflect_obj->hasMethod('afterIndex')) {$reflect_obj_after_index = $reflect_obj->getMethod('afterIndex');$reflect_obj_after_index->isPublic() && $reflect_obj_after_index->invoke($reflect_instance);}$reflect_obj->getMethod('test')->invoke($reflect_instance);} else {echo 'Index 方法不是公有的,不能調用';}} else {echo '沒有index方法,不允許調用';} } else {echo '這個類不存在,不允許調用'; } //輸出 //this is beforeIndex method //this is index method //this is afterIndex method //this is test method ?>?
轉載于:https://www.cnblogs.com/rickyctbu/p/10577627.html
總結
以上是生活随笔為你收集整理的php 常用的知识点归集(下)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 国际标准颜色代码?
- 下一篇: mobaxterm怎么创建连接linux