Sichtbarkeit

Die Sichtbarkeit einer Eigenschaft, Methode oder (von PHP 7.1.0 an) einer Konstante kann definiert werden, indem man der Deklaration eines der Schlüsselwörter public, protected oder private voranstellt. Auf public deklarierte Elemente kann von überall her zugegriffen werden. Protected beschränkt den Zugang auf Elternklassen und abgeleitete Klassen (sowie die Klasse, die das Element definiert). Private grenzt die Sichtbarkeit einzig auf die Klasse ein, die das Element definiert.

Sichtbarkeit von Membern

Klasseneigenschaften können als public, private oder protected definiert werden. Eigenschaften, die ohne explizites Schlüsselwort für die Sichtbarkeit deklariert sind, werden als public definiert.

Beispiel #1 Deklarieren von Eigenschaften

<?php
/**
 * Definiere MyClass
 */
class MyClass
{
    public $public = 'Public';
    protected $protected = 'Protected';
    private $private = 'Private';

    function printHello()
    {
        echo $this->public;
        echo $this->protected;
        echo $this->private;
    }
}

$obj = new MyClass();
echo $obj->public; // Funktioniert
echo $obj->protected; // Fataler Fehler
echo $obj->private; // Fataler Fehler
$obj->printHello(); // Zeigt Public, Protected und Private


/**
 * Definiere MyClass2
 */
class MyClass2 extends MyClass
{
    // Wir können die public- und protected-Eigenschaften neu deklarieren,
    // aber nicht die private
    public $public = 'Public2';
    protected $protected = 'Protected2';

    function printHello()
    {
        echo $this->public;
        echo $this->protected;
        echo $this->private;
    }
}

$obj2 = new MyClass2();
echo $obj2->public; // Funktioniert
echo $obj2->protected; // Fataler Fehler
echo $obj2->private; // Undefiniert
$obj2->printHello(); // Zeigt Public2, Protected2, Undefined

?>

Asymmetrische Sichtbarkeit von Eigenschaften

Seit PHP 8.4 kann die Sichtbarkeit von Eigenschaften auch asymmetrisch festgelegt werden, mit unterschiedlichem Geltungsbereich für Lesen (get) und Schreiben (set). Insbesondere kann die Sichtbarkeit von set separat spezifiziert werden, vorausgesetzt, sie erlaubt nicht mehr als die standardmäßige Sichtbarkeit.

Beispiel #2 Asymmetrische Sichtbarkeit von Eigenschaften

<?php
class Book
{
    public function __construct(
        public private(set) string $title,
        public protected(set) string $author,
        protected private(set) int $pubYear,
    ) {}
}

class SpecialBook extends Book
{
    public function update(string $author, int $year): void
    {
        $this->author = $author; // OK
        $this->pubYear = $year; // Fataler Fehler
    }
}

$b = new Book('How to PHP', 'Peter H. Peterson', 2024);

echo $b->title; // Funktioniert
echo $b->author; // Funktioniert
echo $b->pubYear; // Fataler Fehler

$b->title = 'How not to PHP'; // Fataler Fehler
$b->author = 'Pedro H. Peterson'; // Fataler Fehler
$b->pubYear = 2023; // Fataler Fehler
?>

Bei der asymmetrischen Sichtbarkeit gibt es ein paar Einschränkungen:

  • Nur typisierte Eigenschaften können eine separate Sichtbarkeit von set haben.
  • Die Sichtbarkeit von set muss dieselbe sein wie get oder restriktiver. Das heißt, public protected(set) und protected protected(set) sind erlaubt, aber protected public(set) führt zu einem Syntaxfehler.
  • Wenn eine Eigenschaft public ist, dann kann die Hauptsichtbarkeit weggelassen werden. Das heißt, public private(set) und private(set) haben das gleiche Ergebnis.
  • Eine Eigenschaft mit der Sichtbarkeit private(set) ist automatisch final und darf in einer Kindklasse nicht neu deklariert werden.
  • Der Zugriff auf eine Eigenschaftsreferenz folgt der Sichtbarkeit von set, nicht get. Das liegt daran, dass eine Referenz verwendet werden kann, um den Eigenschaftswert zu ändern.
  • In ähnlicher Weise beinhaltet der Versuch, in eine Array-Eigenschaft zu schreiben, intern sowohl eine get- als auch eine set-Operation und folgt daher der Sichtbarkeit von set, da diese immer die restriktivere ist.

Hinweis: Leerzeichen sind in der Sichtbarkeitsdeklaration von set nicht erlaubt. private(set) ist korrekt. private( set ) ist nicht korrekt und führt zu einem Parser-Fehler.

Wenn eine Klasse eine andere erweitert, kann die Kindklasse jede Eigenschaft, die nicht final ist, neu definieren. Dabei kann sie entweder die Hauptsichtbarkeit oder die Sichtbarkeit von set erweitern, vorausgesetzt, die neue Sichtbarkeit ist gleich oder größer als die der Elternklasse. Es ist jedoch zu beachten, dass eine private Eigenschaft, die überschrieben wird, nicht die Eigenschaft der Elternklasse ändert, sondern eine neue Eigenschaft mit einem anderen internen Namen erzeugt.

Beispiel #3 Vererbung asymmetrischer Eigenschaften

<?php
class Book
{
    protected string $title;
    public protected(set) string $author;
    protected private(set) int $pubYear;
}

class SpecialBook extends Book
{
    public protected(set) string $title; // OK, da die Rechte zum Lesen breiter sind und die zum Schreiben gleich.
    public string $author; // OK, da die Rechte zum Lesen gleich sind und die zum Schreiben breiter.
    public protected(set) int $pubYear; // Fatal Fehler. private(set)-Eigenschaften sind final.
}
?>

Sichtbarkeit von Methoden

Klassenmethoden müssen mit public, private oder protected definiert werden. Methoden ohne jede explizite Deklaration sind als public definiert.

Beispiel #4 Deklarieren von Methoden

<?php
/**
 * Definiere MyClass
 */
class MyClass
{
    // Deklariert einen public Konstruktor
    public function __construct() { }

    // Deklariere eine public Funktion
    public function MyPublic() { }

    // Deklariere eine protected Funktion
    protected function MyProtected() { }

    // Deklariere eine private Funktion
    private function MyPrivate() { }

    // Dies ist public
    function Foo()
    {
        $this->MyPublic();
        $this->MyProtected();
        $this->MyPrivate();
    }
}

$myclass = new MyClass;
$myclass->MyPublic(); // Funktioniert
$myclass->MyProtected(); // Fataler Fehler
$myclass->MyPrivate(); // Fataler Fehler
$myclass->Foo(); // Public, Protected und Private funktionieren


/**
 * Definiere MyClass2
 */
class MyClass2 extends MyClass
{
    // Dies ist public
    function Foo2()
    {
        $this->MyPublic();
        $this->MyProtected();
        $this->MyPrivate(); // Fataler Fehler
    }
}

$myclass2 = new MyClass2;
$myclass2->MyPublic(); // Funktioniert
$myclass2->Foo2(); // Public und Protected funktionieren, Private nicht

class Bar
{
    public function test() {
        $this->testPrivate();
        $this->testPublic();
    }

    public function testPublic() {
        echo "Bar::testPublic\n";
    }

    private function testPrivate() {
        echo "Bar::testPrivate\n";
    }
}

class Foo extends Bar
{
    public function testPublic() {
        echo "Foo::testPublic\n";
    }

    private function testPrivate() {
        echo "Foo::testPrivate\n";
    }
}

$myFoo = new Foo();
$myFoo->test(); // Bar::testPrivate
                // Foo::testPublic
?>

Sichtbarkeit von Konstanten

Von PHP 7.1.0 an können Klassenkonstanten als public, private, oder protected definiert werden. Konstanten, die ohne eine explizite Sichtbarkeitsangabe deklariert wurden, sind public.

Beispiel #5 Deklarieren von Konstanten von PHP 7.1.0 an

<?php
/**
 * Definiere MyClass
 */
class MyClass
{
    // Deklariere eine öffentliche Konstante
    public const MY_PUBLIC = 'öffentlich';

    // Deklariere eine geschützte Konstante
    protected const MY_PROTECTED = 'geschützt';

    // Deklariere eine private Konstante
    private const MY_PRIVATE = 'privat';

    public function foo()
    {
        echo self::MY_PUBLIC;
        echo self::MY_PROTECTED;
        echo self::MY_PRIVATE;
    }
}

$myclass = new MyClass();
MyClass::MY_PUBLIC; // funktioniert
MyClass::MY_PROTECTED; // fataler Fehler
MyClass::MY_PRIVATE; // fataler Fehler
$myclass->foo(); // öffentlich, geschützt und private funktioniert


/**
 * Definiere MyClass2
 */
class MyClass2 extends MyClass
{
    // Dies ist öffentlich
    function foo2()
    {
        echo self::MY_PUBLIC;
        echo self::MY_PROTECTED;
        echo self::MY_PRIVATE; // fataler Fehler
    }
}

$myclass2 = new MyClass2;
echo MyClass2::MY_PUBLIC; // funktioniert
$myclass2->foo2(); // öffentlich und geschützt funktioniert, aber nicht privat
?>

Sichtbarkeit von anderen Objekten

Objekte des gleichen Types haben untereinander Zugriff auf die als private und protected markierten Member, obwohl es sich nicht um die gleichen Instanzen handelt. Dies liegt daran, dass die Details über die Implementierung innerhalb solcher Objekte bekannt sind.

Beispiel #6 Zugriff auf als private markierte Member des gleichen Objekttyps

<?php
class Test
{
    private $foo;

    public function __construct($foo)
    {
        $this->foo = $foo;
    }

    private function bar()
    {
        echo 'Zugriff auf die private Methode';
    }

    public function baz(Test $other)
    {
        // Ändern der privaten Eigenschaft ist möglich:
        $other->foo = 'Hallo';
        var_dump($other->foo);

        // Aufruf der privaten Methode ist ebenfalls möglich:
        $other->bar();
    }
}

$test = new Test('test');

$test->baz(new Test('other'));
?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

string(5) "Hallo"
Zugriff auf die private Methode
+
add a note

User Contributed Notes 6 notes

up
60
pgl at yoyo dot org
10 years ago
Just a quick note that it's possible to declare visibility for multiple properties at the same time, by separating them by commas.

eg:

<?php
class a
{
    protected $a, $b;

    public $c, $d;

    private $e, $f;
}
?>
up
11
Joshua Watt
19 years ago
I couldn't find this documented anywhere, but you can access protected and private member varaibles in different instance of the same class, just as you would expect

i.e.

<?php
class A
{
    protected $prot;
    private $priv;
    
    public function __construct($a, $b)
    {
        $this->prot = $a;
        $this->priv = $b;
    }
    
    public function print_other(A $other)
    {
        echo $other->prot;
        echo $other->priv;
    }
}

class B extends A
{
}

$a = new A("a_protected", "a_private");
$other_a = new A("other_a_protected", "other_a_private");

$b = new B("b_protected", "ba_private");

$other_a->print_other($a); //echoes a_protected and a_private
$other_a->print_other($b); //echoes b_protected and ba_private

$b->print_other($a); //echoes a_protected and a_private
?>
up
7
jc dot flash at gmail dot com
14 years ago
if not overwritten, self::$foo in a subclass actually refers to parent's self::$foo 
<?php
class one
{
    protected static $foo = "bar";
    public function change_foo($value)
    {
        self::$foo = $value;
    }
}

class two extends one
{
    public function tell_me()
    {
        echo self::$foo;
    }
}
$first = new one;
$second = new two;

$second->tell_me(); // bar
$first->change_foo("restaurant");
$second->tell_me(); // restaurant
?>
up
3
alperenberatdurmus at gmail dot com
3 years ago
Dynamic properties are "public".
<?php
class MyClass {
    public function setProperty($value) {
        $this->dynamicProperty = $value;
    }
}
$obj = new MyClass();
$obj->setProperty('Hello World');
echo $obj->dynamicProperty; // Outputs "Hello World"
?>

This usage is the same as well:
<?php
class MyClass {
}
$obj = new MyClass();
$obj->dynamicProperty = 'Hello World';
echo $obj->dynamicProperty; // Outputs "Hello World"
?>
up
5
bishop at php dot net
9 years ago
> Members declared protected can be accessed only within 
> the class itself and by inherited classes. Members declared 
> as private may only be accessed by the class that defines 
> the member.

This is not strictly true. Code outside the object can get and set private and protected members:

<?php
class Sealed { private $value = 'foo'; }

$sealed = new Sealed;
var_dump($sealed); // private $value => string(3) "foo"

call_user_func(\Closure::bind(
    function () use ($sealed) { $sealed->value = 'BAZ'; },
    null,
    $sealed
));

var_dump($sealed); // private $value => string(3) "BAZ"

?>

The magic lay in \Closure::bind, which allows an anonymous function to bind to a particular class scope. The documentation on \Closure::bind says:

> If an object is given, the type of the object will be used
> instead. This determines the visibility of protected and
> private methods of the bound object.

So, effectively, we're adding a run-time setter to $sealed, then calling that setter. This can be elaborated to generic functions that can force set and force get object members:

<?php
function force_set($object, $property, $value) {
    call_user_func(\Closure::bind(
        function () use ($object, $property, $value) {
            $object->{$property} = $value;
        },
        null,
        $object
    ));
}

function force_get($object, $property) {
    return call_user_func(\Closure::bind(
        function () use ($object, $property) {
            return $object->{$property};
        },
        null,
        $object
    ));
}

force_set($sealed, 'value', 'quux');
var_dump(force_get($sealed, 'value')); // 'quux'

?>

You should probably not rely on this ability for production quality code, but having this ability for debugging and testing is handy.
up
1
kostya at eltexsoft dot com
4 years ago
I see we can redeclare private properties into child class 
<?php   
 class A{
        private int $private_prop = 4;
        protected int $protected_prop = 8;
    }

    class B extends A{
        private int $private_prop = 7; // we can redeclare private property!!!
        public function printAll() {
            echo $this->private_prop;
            echo $this->protected_prop;
    }
    }

    $b = new B;
    $b->printAll(); // show 78
}
?>
To Top