php - variable - protected private




公共,私人和受保護之間有什麼區別? (10)

何時以及為什麼要在課堂中使用publicprivateprotected函數和變量? 他們有什麼區別?

例子:

// Public
public $variable;
public function doSomething() {
  // ...
}

// Private
private $variable;
private function doSomething() {
  // ...
}

// Protected
protected $variable;
protected function doSomething() {
  // ...
}

Here️這是一個簡單的方法來記住publicprotectedprivate的範圍。

PUBLIC

  • public範圍:公共變量/函數可用於對象和其他類。

PROTECTED

  • protected範圍:受保護的變量/函數可用於擴展當前類的所有類。
  • 沒有! 對象無法訪問此範圍

PRIVATE

  • private範圍:私有變量/函數僅在當前定義的類中可見。
  • 沒有! 擴展當前類的類不能訪問此作用域。
  • 沒有! 對象無法訪問此範圍。

閱讀PHP Manual上的方法或變量的http://php.net/manual/en/language.oop5.visibility.php


PHP中的變量分為三種類型:

Public:這個變量類型的值在所有範圍內都可用,並且調用執行你的代碼。 聲明為: public $examTimeTable;

私有:這種類型的變量的值只能用於它所屬的類。 private $classRoomComputers;

受保護:僅限此類的值,並且僅在Access以繼承形式或其子類授予時才可用。 通常用於::授予父類的訪問權限

protected $familyWealth;


Public:當你聲明一個變量或方法時,它是一個默認狀態,可以通過任何東西直接訪問該對象。

受保護:只能在對象和子類中訪問。

私有:只能在對像中引用,而不能在子類中引用。



具有抽象示例的 可見性範圍 :: 易於理解

這種屬性或方法的可見性是通過三個關鍵字(Public,protected和private)之一的預先固定聲明來定義的,

公開 :如果一個屬性或方法被定義為公共的,這意味著它可以被任何可以引用對象的東西訪問和操縱。

  • 摘要例如。 把公眾的視野範圍看作任何人都可以來的“公共野餐”

受保護:當屬性或方法可見性設置為受保護成員時,只能在類本身以及繼承和繼承類中進行訪問。 (繼承: - 一個類可以擁有另一個類的所有屬性和方法)。

  • 將公司成員及其家庭成員不允許公開的情況視為“公司野餐”的保護範圍。 這是最常見的範圍限制。

私有:當屬性或方法可見性設置為私有時,只有具有私有成員的類可以訪問這些方法和屬性(在類內部),儘管可能存在任何類關係。

  • 野餐比喻認為是野餐中“只有公司成員可以參加的公司野餐”。 不是家庭,也不是普通公眾。

區別如下:

Public ::公共變量或方法可以由任何類的用戶直接訪問。

Protected ::受保護的變量或方法不能由類的用戶訪問,但可以在繼承自類的子類內訪問。

Private ::私有變量或方法只能從定義它的類內部訪問。這意味著不能從擴展類的子級調用私有變量或方法。


復興一個老問題,但我認為想到這個問題的一個好方法就是根據您定義的API。

  • public - 標記為public的所有內容都是API的一部分,任何使用您的class / interface / other的人都將使用並依賴它。

  • protected - 不要被愚弄,這也是API的一部分! 人們可以繼承,擴展你的代碼並使用標記為protected的任何東西。

  • private - 私人財產和方法可以隨意更改。 沒有人可以使用這些。 這些是唯一可以在不做任何突變的情況下進行更改的內容。

或者用Semver來說:

  • 對任何publicprotected進行更改應視為主要更改。

  • 任何新的publicprotected應該是(至少)MINOR

  • 只有新的/改變任何private可以PATCH

因此,在維護代碼方面,請謹慎對待您publicprotected因為這些是您向用戶承諾的內容。


私人 - 只能在課堂內進行訪問

保護 - 可以從類和INHERITING類中進行訪問

公開 - 可以從課堂外的代碼訪問

這適用於函數以及變量。


默認情況下,通常認為這是一種很好的做法,因為這可以促進數據封裝和良好的界面設計。 在考慮成員變量和方法可見性時,考慮成員在與其他對象的交互中扮演的角色。

如果你“編碼到接口而不是實現”,那麼做出可視化決策通常是非常簡單的。 一般來說,變量應該是私人的或保護的,除非你有充分的理由暴露它們。 使用公共訪問器(getter / setter)來限制和管理對類內部的訪問。

以汽車為例,速度,裝備和方向等都是私人實例變量。 你不希望駕駛員直接操縱空氣/燃料比例。 相反,您將公開的方法暴露的數量有限。 汽車的接口可能包括accelerate()deccelerate() / brake()setGear()turnLeft()turnRight()等方法。

司機不知道也不應該關心汽車內部的這些行為是如何實施的,並且暴露該功能可能對司機和其他人造成危險。 因此,設計一個公共接口並將數據封裝在該接口後面的好習慣。

這種方法還允許您在不破壞接口與客戶端代碼的契約的情況下,改變和改進類中公共方法的實現。 例如,您可以改進accelerate()方法以提高燃油效率,但該方法的使用將保持不變; 客戶端代碼不需要更改,但仍然可以從效率提升中獲益。

編輯:由於看起來你仍然處於學習面向對象的概念(比任何語言的語法更難掌握),所以我強烈建議你拿起Matt Zandstra提供的PHP Objects,Patterns和Practice的副本。 這本書首先教會了我如何有效地使用OOP,而不僅僅是教給我語法。 我幾年前就已經學會了語法,但是在沒有理解OOP的“為什麼”的情況下這是沒用的。


上市:

當您將方法(函數)或屬性(變量)聲明為public ,可以通過以下方式訪問這些方法和屬性:

  • 宣布它的同一個類。
  • 繼承上面聲明的類的類。
  • 這個班級以外的任何外來人員也可以訪問這些內容。

例:

<?php

class GrandPa
{
    public $name='Mark Henry';  // A public variable
}

class Daddy extends GrandPa // Inherited class
{
    function displayGrandPaName()
    {
        return $this->name; // The public variable will be available to the inherited class
    }

}

// Inherited class Daddy wants to know Grandpas Name
$daddy = new Daddy;
echo $daddy->displayGrandPaName(); // Prints 'Mark Henry'

// Public variables can also be accessed outside of the class!
$outsiderWantstoKnowGrandpasName = new GrandPa;
echo $outsiderWantstoKnowGrandpasName->name; // Prints 'Mark Henry'

保護:

當您將方法(函數)或屬性(變量)聲明為protected ,可以通過訪問這些方法和屬性

  • 宣布它的同一個類。
  • 繼承上面聲明的類的類。

局外人成員不能訪問這些變量。 “局外人”是指它們不是被聲明的類本身的對象實例。

例:

<?php

class GrandPa
{
    protected $name = 'Mark Henry';
}

class Daddy extends GrandPa
{
    function displayGrandPaName()
    {
        return $this->name;
    }

}

$daddy = new Daddy;
echo $daddy->displayGrandPaName(); // Prints 'Mark Henry'

$outsiderWantstoKnowGrandpasName = new GrandPa;
echo $outsiderWantstoKnowGrandpasName->name; // Results in a Fatal Error

確切的錯誤將是這樣的:

PHP致命錯誤:無法訪問受保護的屬性GrandPa :: $ name

私人的:

當您將方法(函數)或屬性(變量)聲明為private ,可以通過以下方式訪問這些方法和屬性:

  • 宣布它的同一個類。

局外人成員不能訪問這些變量。 局外人的意義在於,它們不是被聲明的類本身的對象實例,甚至是繼承聲明的類的類。

例:

<?php

class GrandPa
{
    private $name = 'Mark Henry';
}

class Daddy extends GrandPa
{
    function displayGrandPaName()
    {
        return $this->name;
    }

}

$daddy = new Daddy;
echo $daddy->displayGrandPaName(); // Results in a Notice 

$outsiderWantstoKnowGrandpasName = new GrandPa;
echo $outsiderWantstoKnowGrandpasName->name; // Results in a Fatal Error

確切的錯誤信息將是:

注意:未定義的屬性:Daddy :: $ name
致命錯誤:無法訪問私有屬性GrandPa :: $ name

使用Reflection解剖爺爺級

這個主題並沒有超出範圍,我在這裡添加它只是為了證明反射真的很強大。 正如我在上面的三個例子中所說的, protectedprivate成員(屬性和方法)不能在課堂外訪問。

但是,通過反思,您甚至可以通過訪問課堂以外的protectedprivate成員來做到超乎尋常的事情!

那麼,反思是什麼?

反思增加了對類,接口,函數,方法和擴展進行反向工程的能力。 另外,它們提供了獲取文檔註釋以獲取函數,類和方法的方法。

前言

我們有一個名為Grandpas的課程,並說我們有三個屬性。 為了便於理解,可以考慮有三個名字為grandpas的人:

  • 馬克亨利
  • 約翰克萊什
  • 威爾瓊斯

讓我們分別將它們(分配修飾符)設置為publicprotectedprivate 。 你很清楚, protectedprivate成員不能在課堂外進行訪問。 現在讓我們用反思來反駁這個陳述。

代碼

<?php

class GrandPas   // The Grandfather's class
{
    public     $name1 = 'Mark Henry';  // This grandpa is mapped to a public modifier
    protected  $name2 = 'John Clash';  // This grandpa is mapped to a protected  modifier
    private    $name3 = 'Will Jones';  // This grandpa is mapped to a private modifier
}


# Scenario 1: without reflection
$granpaWithoutReflection = new GrandPas;

# Normal looping to print all the members of this class
echo "#Scenario 1: Without reflection<br>";
echo "Printing members the usual way.. (without reflection)<br>";
foreach($granpaWithoutReflection as $k=>$v)
{
    echo "The name of grandpa is $v and he resides in the variable $k<br>";
}

echo "<br>";

#Scenario 2: Using reflection

$granpa = new ReflectionClass('GrandPas'); // Pass the Grandpas class as the input for the Reflection class
$granpaNames=$granpa->getDefaultProperties(); // Gets all the properties of the Grandpas class (Even though it is a protected or private)


echo "#Scenario 2: With reflection<br>";
echo "Printing members the 'reflect' way..<br>";

foreach($granpaNames as $k=>$v)
{
    echo "The name of grandpa is $v and he resides in the variable $k<br>";
}

輸出:

#Scenario 1: Without reflection
Printing members the usual way.. (Without reflection)
The name of grandpa is Mark Henry and he resides in the variable name1

#Scenario 2: With reflection
Printing members the 'reflect' way..
The name of grandpa is Mark Henry and he resides in the variable name1
The name of grandpa is John Clash and he resides in the variable name2
The name of grandpa is Will Jones and he resides in the variable name3

常見的誤解:

請不要混淆下面的例子。 正如您仍然可以看到的, privateprotected成員不能在不使用反射的情況下在課程之外訪問

<?php

class GrandPas   // The Grandfather's class
{
    public     $name1 = 'Mark Henry';  // This grandpa is mapped to a public modifier
    protected  $name2 = 'John Clash';  // This grandpa is mapped to a protected modifier
    private    $name3 = 'Will Jones';  // This grandpa is mapped to a private modifier
}

$granpaWithoutReflections = new GrandPas;
print_r($granpaWithoutReflections);

輸出:

GrandPas Object
(
    [name1] => Mark Henry
    [name2:protected] => John Clash
    [name3:GrandPas:private] => Will Jones
)

調試功能

print_rvar_exportvar_dump調試器函數 。 他們以可讀的形式呈現有關變量的信息。 這三個函數將使用PHP 5揭示對象的protected屬性和private屬性。靜態類成員將不會顯示。

更多資源:





protected