首頁 後端開發 php教程 PHP的Yii框架中的屬性Property

PHP的Yii框架中的屬性Property

Nov 13, 2017 am 11:50 AM
php yii 框架

Yii是一個基於元件的高效能PHP框架,用於開發大型網路應用。 Yii採用嚴格的OOP編寫,並有著完善的函式庫引用以及全面的教學。從 MVC,DAO/ActiveRecord,widgets,caching,等級式RBAC,Web服務,到主題化,I18N和L10N,Yii提供了今日Web 2.0應用開發所需的幾乎一切功能。事實上,Yii是最有效率的PHP框架之一。

Yii是一個高效能的PHP5的web應用程式開發框架。透過一個簡單的命令列工具 yiic 可以快速創建一個web應用程式的程式碼框架,開發者可以在生成的程式碼框架基礎上添加業務邏輯,以快速完成應用程式的開發。

在 PHP 中,類別的成員變數也稱為屬性(properties)。它們是類別定義的一部分,用來表現一個實例的狀態(也就是區分類的不同實例)。在具體實踐中,常常會想用一個稍微特殊些的方法來實現屬性的讀寫。例如,如果有需求每次都要對 label 屬性執行 trim 操作,就可以用以下程式碼實作:

$object->label = trim($label);
登入後複製

上述程式碼的缺點是只要修改 label 屬性就必須再次呼叫 trim() 函數。若將來需要用其它方式處理 label 屬性,例如首字母大寫,就必須修改所有給 label 屬性賦值的程式碼。這種程式碼的重複會導致 bug,這種實踐顯然需要盡可能避免。

為解決這個問題,Yii 引入了一個名為 yii\base\Object 的基類,它支援基於類別內的 getter 和 setter(讀取器和設定器)方法來定義屬性。如果某一類別需要支援這個特性,只需要繼承 yii\base\Object 或其子類別。

補充:幾乎每個 Yii 框架的核心類別都繼承自 yii\base\Object 或其子類別。這意味著只要在核心類別中見到 getter 或 setter 方法,就可以像呼叫屬性一樣呼叫它。
getter 方法是名稱以 get 開頭的方法,而 setter 方法名稱以 set 開頭。方法名稱中 get 或 set 後面的部分就定義了該屬性的名字。如下面程式碼所示,getter 方法getLabel() 和setter 方法setLabel() 操作的是label 屬性,:

namespace app\components;
use yii\base\Object;
class Foo extend Object
{
  private $_label;
  public function getLabel()
  {
    return $this->_label;
  }
  public function setLabel($value)
  {
    $this->_label = trim($value);
  }
}
登入後複製

(詳細解釋:getter 和setter 方法建立了一個名為label 的屬性,在這個在範例裡,它指向一個私有的內部屬性_label。兩者主要的差異是:當這種屬性被讀取時,對應的 getter 方法將被呼叫;而當屬性被賦值時,對應的 setter 方法就會被呼叫。如:

// 等效于 $label = $object->getLabel();
$label = $object->label;
// 等效于 $object->setLabel('abc');
$object->label = 'abc';
登入後複製

只定義了 getter 沒有 setter 的屬性是唯讀屬性。嘗試賦值給這樣的屬性將導致 yii\base\InvalidCallException (無效呼叫)異常。類似的,只有 setter 方法而沒有 getter 方法定義的屬性是只寫屬性,嘗試讀取這種屬性也會觸發異常。使用只寫屬性的情況幾乎沒有。

透過 getter 和 setter 定義的屬性也有一些特殊規則和限制:

這類屬性的名字是不區分大小寫的。如,$object->label 和 $object->Label 是同一個屬性。因為 PHP 方法名稱是不區分大小寫的。

如果此類屬性名和類別成員變數相同,則以後者為準。例如,假設以上 Foo 類別有個 label 成員變量,然後給 $object->label = 'abc' 賦值,將賦給成員變數而不是 setter setLabel() 方法。

這類屬性不支援可見性(存取限制)。定義屬性的 getter 和 setter 方法是 public、protected 還是 private 對屬性的可見性沒有任何影響。
這類屬性的 getter 和 setter 方法只能定義為非靜態的,若定義為靜態方法(static)則不會以相同方式處理。
回到開頭提到的問題,與其處處要呼叫 trim() 函數,現在我們只需在 setter setLabel() 方法內呼叫一次。如果 label 首字母變成大寫的新要求來了,我們只需要修改setLabel() 方法,而無須接觸任何其它程式碼。

實作屬性的步驟

我們知道,在讀取和寫入物件的一個不存在的成員變數時, __get() __set() 會被自動呼叫。 Yii正是利用這一點,提供對屬性的支援的。從上面的程式碼中,可以看出,如果存取一個物件的某個屬性, Yii會呼叫名為 get屬性名() 的函數。如, SomeObject->Foo , 會自動呼叫 SomeObject->getFoo() 。如果修改某一屬性,會呼叫對應的setter函數。 如, SomeObject->Foo = $someValue ,會自動呼叫 SomeObject->setFoo($someValue) 。

因此,要實作屬性,通常有三個步驟:

繼承自 yii\base\Object 。

宣告一個用來保存該屬性的私有成員變數。

提供getter或setter函數,或兩者都提供,用於存取、修改上面提到的私有成員變數。 如果只提供了getter,那麼屬性為唯讀屬性,只提供了setter,則為唯寫。

如下的Post類,實作了可讀可寫的屬性title:

class Post extends yii\base\Object  // 第一步:继承自 yii\base\Object
{
  private $_title;         // 第二步:声明一个私有成员变量
  public function getTitle()    // 第三步:提供getter和setter
  {
    return $this->_title;
  }
  public function setTitle($value)
  {
    $this->_title = trim($value);
  }
}
登入後複製

从理论上来讲,将 private $_title 写成 public $title ,也是可以实现对 $post->title 的读写的。但这不是好的习惯,理由如下:

失去了类的封装性。 一般而言,成员变量对外不可见是比较好的编程习惯。 从这里你也许没看出来,但是假如有一天,你不想让用户修改标题了,你怎么改? 怎么确保代码中没有直接修改标题? 如果提供了setter,只要把setter删掉,那么一旦有没清理干净的对标题的写入,就会抛出异常。 而使用 public $title 的方法的话,你改成 private $title 可以排查写入的异常,但是读取的也被禁止了。
对于标题的写入,你想去掉空格。 使用setter的方法,只需要像上面的代码段一样在这个地方调用 trim() 就可以了。 但如果使用 public $title 的方法,那么毫无疑问,每个写入语句都要调用 trim() 。 你能保证没有一处遗漏?
因此,使用 public $title 只是一时之快,看起来简单,但今后的修改是个麻烦事。 简直可以说是恶梦。这就是软件工程的意义所在,通过一定的方法,使代码易于维护、便于修改。 一时看着好像没必要,但实际上吃过亏的朋友或者被客户老板逼着修改上一个程序员写的代码,问候过他亲人的, 都会觉得这是十分必要的。

但是,世事无绝对。由于 __get() 和 __set() 是在遍历所有成员变量,找不到匹配的成员变量时才被调用。 因此,其效率天生地低于使用成员变量的形式。在一些表示数据结构、数据集合等简单情况下,且不需读写控制等, 可以考虑使用成员变量作为属性,这样可以提高一点效率。

另外一个提高效率的小技巧就是:使用 $pro = $object->getPro() 来代替 $pro = $object->pro , 用 $objcect->setPro($value) 来代替 $object->pro = $value 。 这在功能上是完全一样的效果,但是避免了使用 __get() 和 __set() ,相当于绕过了遍历的过程。

这里估计有人该骂我了,Yii好不容易实现了属性的机制,就是为了方便开发者, 结果我却在这里教大家怎么使用原始的方式,去提高所谓的效率。 嗯,确实,开发的便利性与执行高效率存在一定的矛盾。我个人的观点更倾向于以便利为先, 用好、用足Yii为我们创造的便利条件。至于效率的事情,更多的是框架自身需要注意的, 我们只要别写出格外2的代码就OK了。

不过你完全可以放心,在Yii的框架中,极少出现 $app->request 之类的代码,而是使用 $app->getRequest() 。 换句话说,框架自身还是格外地注重效率的,至于便利性,则留给了开发者。 总之,这里只是点出来有这么一个知识点,至于用不用,怎么用,完全取决于你了。

值得注意的是:

由于自动调用 __get() __set() 的时机仅仅发生在访问不存在的成员变量时。 因此,如果定义了成员变量 public $title 那么,就算定义了 getTitle() setTitle() , 他们也不会被调用。因为 $post->title 时,会直接指向该 pulic $title , __get() __set() 是不会被调用的。从根上就被切断了。
由于PHP对于类方法不区分大小写,即大小写不敏感, $post->getTitle() 和 $post->gettitle() 是调用相同的函数。 因此, $post->title 和 $post->Title 是同一个属性。即属性名也是不区分大小写的。
由于 __get() __set() 都是public的, 无论将 getTitle() setTitle() 声明为 public, private, protected, 都没有意义,外部同样都是可以访问。所以,所有的属性都是public的。
由于 __get() __set() 都不是static的,因此,没有办法使用static 的属性。
Object的其他与属性相关的方法

除了 __get() __set() 之外, yii\base\Object 还提供了以下方法便于使用属性:

__isset() 用于测试属性值是否不为 null ,在 isset($object->property) 时被自动调用。 注意该属性要有相应的getter。

__unset() 用于将属性值设为 null ,在 unset($object->property) 时被自动调用。 注意该属性要有相应的setter。

hasProperty() 用于测试是否有某个属性。即,定义了getter或setter。 如果 hasProperty() 的参数 $checkVars = true (默认为true), 那么只要具有同名的成员变量也认为具有该属性,如前面提到的 public $title 。

canGetProperty() 测试一个属性是否可读,参数 $checkVars 的意义同上。只要定义了getter,属性即可读。 同时,如果 $checkVars 为 true 。那么只要类定义了成员变量,不管是public, private 还是 protected, 都认为是可读。

canSetProperty() 測試一個屬性是否可寫,參數 $checkVars 的意義同上。只要定義了setter,屬性即可寫入。 同時,在 $checkVars 為 ture 。那麼只要類別定義了成員變量,不管是public, private 還是 protected, 都認為是可寫。

Object和Component

yii\base\Component 繼承自 yii\base\Object ,因此,他也具有屬性等基本功能。

但是,由於Componet也引入了事件、行為,因此,它並非簡單地繼承了Object的屬性實作方式,而是基於相同的機制, 重載了 __get() __set() 等函數。但從實現機制上來講,是一樣的。這個不影響理解。

前面說過,官方將Yii定位在一個基於組件的框架。可見組件這一概念是Yii的基礎。 如果你有興趣閱讀Yii的原始碼或是API文檔,你將會發現, Yii幾乎所有的核心類別都派生於(繼承自) yii\base\Component 。

在Yii1.1時,就已經有了component了,那時是 CComponent。 Yii2將Yii1.1中的CComponent分割成兩個類別: yii\base\Object 和 yii\base\Component 。

其中,Object比較輕量級些,透過getter和setter定義了類別的屬性(property)。 Component派生自Object,並支援事件(event)和行為(behavior)。因此,Component類別具有三個重要的特性:

屬性(property)

事件(event)

#行為(behavior)

相信你或多或少了解過,這三個特性是豐富和拓展類功能、改變類行為的重要切入點。 因此,Component在Yii中的地位極高。

在提供更多功能、更多便利的同時,Component由於增加了event和behavior這兩個特性, 在方便開發的同時,也犧牲了一定的效率。 如果開發中不需要使用event和behavior這兩個特性,例如表示一些資料的類別。 那麼,可以不從Component繼承,而從Object繼承。 典型的應用場景就是如果表示使用者輸入的一組數據,那麼,使用Object。 而如果需要對物件的行為和能響應處理的事件進行處理,毫無疑問地應採用Component。 從效率來講,Object更接近原生的PHP類,因此,在可能的情況下,應優先使用Object。

相關推薦:

Yii2.0框架入門與實戰專案開發影片教學

Yii2中文手冊

從零開始打造自己的PHP框架

以上是PHP的Yii框架中的屬性Property的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

適用於 Ubuntu 和 Debian 的 PHP 8.4 安裝和升級指南 適用於 Ubuntu 和 Debian 的 PHP 8.4 安裝和升級指南 Dec 24, 2024 pm 04:42 PM

PHP 8.4 帶來了多項新功能、安全性改進和效能改進,同時棄用和刪除了大量功能。 本指南介紹如何在 Ubuntu、Debian 或其衍生版本上安裝 PHP 8.4 或升級到 PHP 8.4

討論 CakePHP 討論 CakePHP Sep 10, 2024 pm 05:28 PM

CakePHP 是 PHP 的開源框架。它旨在使應用程式的開發、部署和維護變得更加容易。 CakePHP 基於類似 MVC 的架構,功能強大且易於掌握。模型、視圖和控制器 gu

如何設定 Visual Studio Code (VS Code) 進行 PHP 開發 如何設定 Visual Studio Code (VS Code) 進行 PHP 開發 Dec 20, 2024 am 11:31 AM

Visual Studio Code,也稱為 VS Code,是一個免費的原始碼編輯器 - 或整合開發環境 (IDE) - 可用於所有主要作業系統。 VS Code 擁有大量針對多種程式語言的擴展,可以輕鬆編寫

CakePHP 快速指南 CakePHP 快速指南 Sep 10, 2024 pm 05:27 PM

CakePHP 是一個開源MVC 框架。它使應用程式的開發、部署和維護變得更加容易。 CakePHP 有許多函式庫可以減少大多數常見任務的過載。

您如何在PHP中解析和處理HTML/XML? 您如何在PHP中解析和處理HTML/XML? Feb 07, 2025 am 11:57 AM

本教程演示瞭如何使用PHP有效地處理XML文檔。 XML(可擴展的標記語言)是一種用於人類可讀性和機器解析的多功能文本標記語言。它通常用於數據存儲

在PHP API中說明JSON Web令牌(JWT)及其用例。 在PHP API中說明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一種基於JSON的開放標準,用於在各方之間安全地傳輸信息,主要用於身份驗證和信息交換。 1.JWT由Header、Payload和Signature三部分組成。 2.JWT的工作原理包括生成JWT、驗證JWT和解析Payload三個步驟。 3.在PHP中使用JWT進行身份驗證時,可以生成和驗證JWT,並在高級用法中包含用戶角色和權限信息。 4.常見錯誤包括簽名驗證失敗、令牌過期和Payload過大,調試技巧包括使用調試工具和日誌記錄。 5.性能優化和最佳實踐包括使用合適的簽名算法、合理設置有效期、

php程序在字符串中計數元音 php程序在字符串中計數元音 Feb 07, 2025 pm 12:12 PM

字符串是由字符組成的序列,包括字母、數字和符號。本教程將學習如何使用不同的方法在PHP中計算給定字符串中元音的數量。英語中的元音是a、e、i、o、u,它們可以是大寫或小寫。 什麼是元音? 元音是代表特定語音的字母字符。英語中共有五個元音,包括大寫和小寫: a, e, i, o, u 示例 1 輸入:字符串 = "Tutorialspoint" 輸出:6 解釋 字符串 "Tutorialspoint" 中的元音是 u、o、i、a、o、i。總共有 6 個元

我後悔之前不知道的 7 個 PHP 函數 我後悔之前不知道的 7 個 PHP 函數 Nov 13, 2024 am 09:42 AM

如果您是經驗豐富的PHP 開發人員,您可能會感覺您已經在那裡並且已經完成了。操作

See all articles