搜尋
首頁後端開發php教程Yii中的屬性(Property)詳解
Yii中的屬性(Property)詳解Dec 29, 2017 pm 07:04 PM
property屬性詳解

本文主要介紹了PHP的Yii框架中的屬性(Property),詳細說明了實現屬性的步驟,需要的朋友可以參考下。希望對大家有幫助。

在 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。

相關推薦:

Yii運作機制及路由詳解

Yii如何隱藏URL中index.php

PHP Yii框架之資料庫查詢操作總結

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

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
PHP Notice: Trying to get property of non-object - 解决方法PHP Notice: Trying to get property of non-object - 解决方法Aug 17, 2023 am 09:27 AM

PHPNotice:Tryingtogetpropertyofnon-object-解决方法在PHP开发过程中,我们可能会遇到一个常见的错误提示:Tryingtogetpropertyofnon-object(试图获取非对象的属性)。这个错误通常是由我们对一个非对象类型的变量尝试访问属性(或调用方法)时引起的。这篇文章将向你介绍这

PHP Notice: Undefined property: 的解决方法PHP Notice: Undefined property: 的解决方法Jun 22, 2023 pm 02:48 PM

在使用PHP编写代码时,我们可能会遇到“Notice:Undefinedproperty”这个错误提示。这个错误提示意味着我们正在访问一个未定义的属性,通常是因为该属性在代码中尚未被初始化。那么,该如何解决这个问题呢?下面是几种可能的解决方法:初始化属性这是解决该问题的最简单方法。在代码中显式地初始化属性,可以确保它在使用前已经被定义。例如:class

Django框架中的缓存机制详解Django框架中的缓存机制详解Jun 18, 2023 pm 01:14 PM

在Web应用程序中,缓存通常是用来优化性能的重要手段。Django作为一款著名的Web框架,自然也提供了完善的缓存机制来帮助开发者进一步提高应用程序的性能。本文将对Django框架中的缓存机制进行详解,包括缓存的使用场景、建议的缓存策略、缓存的实现方式和使用方法等方面。希望对Django开发者或对缓存机制感兴趣的读者有所帮助。一、缓存的使用场景缓存的使用场景

php-fpm调优方法详解php-fpm调优方法详解Jul 08, 2023 pm 04:31 PM

PHP-FPM是一种常用的PHP进程管理器,用于提供更好的PHP性能和稳定性。然而,在高负载环境下,PHP-FPM的默认配置可能无法满足需求,因此我们需要对其进行调优。本文将详细介绍PHP-FPM的调优方法,并给出一些代码示例。一、增加进程数默认情况下,PHP-FPM只启动少量的进程来处理请求。在高负载环境下,我们可以通过增加进程数来提高PHP-FPM的并发

PHP function_exists()函数用法详解PHP function_exists()函数用法详解Jun 27, 2023 am 10:32 AM

在PHP开发中,有时我们需要判断某个函数是否可用,这时我们便可以使用function_exists()函数。本文将详细介绍function_exists()函数的用法。一、什么是function_exists()函数?function_exists()函数是PHP自带的一个内置函数,用于判断某个函数是否被定义。该函数返回一个布尔值,如果函数存在返回True,

Gin框架的模板渲染功能详解Gin框架的模板渲染功能详解Jun 22, 2023 pm 10:37 PM

Gin框架是目前非常流行的Go语言Web框架之一。作为一个轻量级的框架,Gin提供了丰富的功能和灵活的架构,使得它在Web开发领域中备受欢迎。其中一个特别重要的功能是模板渲染。在本文中,我们将介绍Gin框架的模板渲染功能,并深入了解它的实现原理。一、Gin框架的模板渲染功能Gin框架使用了多种模板渲染引擎来构建Web应用程序。目前,它支持以下几种模板引擎:

PHP中的ORM框架使用详解PHP中的ORM框架使用详解Jun 23, 2023 am 11:22 AM

ORM(Object-RelationalMapping)框架是一种用于将面向对象编程语言中的对象模型与关系型数据库之间映射的技术。它使开发人员能够使用面向对象的方式操作数据库,而不需要直接操作SQL语言。在PHP开发领域中,ORM框架也得到了广泛的应用。本文将详细介绍PHP中的ORM框架使用方法。一、ORM框架的优点使用ORM框架有以下优点:1.提高开发

PHP strpos()函数用法详解PHP strpos()函数用法详解Jun 27, 2023 am 10:43 AM

PHPstrpos()函数用法详解在PHP编程中,字符串处理是非常重要的一部分。PHP通过提供一些内置函数来实现字符串处理。其中,strpos()函数就是PHP中最常用的一个字符串函数之一。该函数的目的是在一个指定的字符串中搜索另一个指定字符串的位置,如果包含则返回这个位置,否则返回false。本文将通过详细分析PHPstrpos()函数的用法,助你更好

See all articles

熱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尊渡假赌尊渡假赌尊渡假赌

熱工具

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。