Die Sichtbarkeit einer Eigenschaft oder Methode 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.
Klasseneigenschaften müssen als public, private oder protected definiert werden. Wenn sie mit var deklariert werden, also ohne ein explizites Sichtbarkeits-Schlüsselwort, werden sie als public deklariert.
Beispiel #1 Eigenschaftendeklaration
<?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-Methoden neu deklarieren,
// aber nicht die private-Methode
protected $protected = 'Protected2';
function printHello()
{
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj2 = new MyClass2();
echo $obj2->public; // Funktioniert
echo $obj2->private; // Undefiniert
echo $obj2->protected; // Fataler Fehler
$obj2->printHello(); // Zeigt Public, Protected2, Undefined
?>
Hinweis: Die PHP-4-Methode, Variablen mit dem Schlüsselwort var zu deklarieren, wird aus Gründen der Abswärtskompatibilität weiterhin unterstützt (als Synonym für das public-Schlüsselwort). In PHP 5 vor 5.1.3 hat dessen Verwendung eine E_STRICT-Warnung erzeugt.
Klassenmethoden müssen mit public, private oder protected definiert werden. Methoden ohne jede explizite Deklaration sind als public definiert.
Beispiel #2 Methodendeklaration
<?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
?>
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 #3 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 +
Here's a bizarre little quirk that I haven't seen mentioned before:
<?php
class ParentClass
{
private $foo;
public function __construct()
{
$this->foo = 'foo';
}
public function foo()
{
echo $this->foo;
}
}
class ChildClass1 extends ParentClass
{
public function bar()
{
echo $this->foo;
}
}
class ChildClass2 extends ParentClass
{
public function __construct()
{
$this->foo = 'bar';
}
public function bar()
{
echo $this->foo;
}
}
$parent = new ParentClass();
$parent->foo(); // "foo"
$child1 = new ChildClass1();
$child1->foo(); // "foo"
$child1->bar(); // "Notice: Undefined property: ChildClass1::$foo in [file] on line [line]"
$child2 = new ChildClass2();
$child2->foo(); // <nothing>
$child2->bar(); // "bar"
?>
The output of ChildClass1::foo() and ChildClass1::bar() are expected given the private visibility of $foo. However, the output of ChildClass2::foo() and ChildClass2::bar() are completely unexpected according to the documentation (to my understanding, at least).
Setting a private property of a parent class in the constructor of a child class is not only possible, but essentially "hijacks" that property away from the parent class.
Please note that protected methods are also available from sibling classes as long as the method is declared in the common parent. This may also be an abstract method.
In the below example Bar knows about the existence of _test() in Foo because they inherited this method from the same parent. It does not matter that it was abstract in the parent.
<?php
abstract class Base {
abstract protected function _test();
}
class Bar extends Base {
protected function _test() { }
public function TestFoo() {
$c = new Foo();
$c->_test();
}
}
class Foo extends Base {
protected function _test() {
echo 'Foo';
}
}
$bar = new Bar();
$bar->TestFoo(); // result: Foo
?>
Some Method Overriding rules :
1. In the overriding, the method names and arguments (arg’s) must be same.
Example:
class p { public function getName(){} }
class c extends P{ public function getName(){} }
2. final methods can’t be overridden.
3. private methods never participate in the in the overriding because these methods are not visible in the child classes.
Example:
class a {
private function my(){
print "parent:my";
}
public function getmy(){
$this->my();
}
}
class b extends a{
private function my(){
print "base:my";
}
}
$x = new b();
$x->getmy(); // parent:my
4. While overriding decreasing access specifier is not allowed
class a {
public function my(){
print "parent:my";
}
}
class b extends a{
private function my(){
print "base:my";
}
}
//Fatal error: Access level to b::my() must be public (as in class a)
If you miss the "package" keyword in PHP in order to allow access between certain classes without their members being public, you can utilize the fact, that in PHP the protected keyword allows access to both subclasses and superclasses.
So you can use this simple pattern:
<?php
abstract class Dispatcher {
protected function &accessProperty (self $pObj, $pName) {
return $pObj->$pName;
}
protected function invokeMethod ($pObj, $pName, $pArgs) {
return call_user_func_array(array($pObj, $pName), $pArgs);
}
}
?>
The classes that should be privileged to each other simply extend this dispatcher:
<?php
class Person extends Dispatcher {
private $name;
protected $phoneNumbers;
public function __construct ($pName) {
$this->name = $pName;
$this->phoneNumbers = array();
}
public function addNumber (PhoneNumber $pNumber, $pLabel) {
$this->phoneNumbers[$pLabel] = $pNumber;
// this does not work, because "owner" is protected:
// $pNumber->owner = $this;
// instead, we get a reference from the dispatcher:
$p =& $this->accessProperty($pNumber, "owner");
// ... and change that:
$p = $this;
}
public function call ($pLabel) {
// this does not work since "call" is protected:
// $this->phoneNumbers[$pLabel]->call();
// instead, we dispatch the call request:
$this->invokeMethod($this->phoneNumbers[$pLabel], "call", array());
}
}
class PhoneNumber extends Dispatcher {
private $countryCode;
private $areaCode;
private $number;
protected $owner;
public function __construct ($pCountryCode, $pAreaCode, $pNumber) {
$this->countryCode = $pCountryCode;
$this->areaCode = $pAreaCode;
$this->number = $pNumber;
}
protected function call () {
echo("calling " . $this->countryCode . "-" . $this->areaCode . "-" . $this->number . "\n");
}
}
$person = new Person("John Doe");
$number1 = new PhoneNumber(12, 345, 67890);
$number2 = new PhoneNumber(34, 5678, 90123);
$person->addNumber($number1, "home");
$person->addNumber($number2, "office");
$person->call("home");
?>
Without this pattern you would have to make $owner and call() public in PhoneNumber.
Best regards,
If you have problems with overriding private methods in extended classes, read this:)
The manual says that "Private limits visibility only to the class that defines the item". That means extended children classes do not see the private methods of parent class and vice versa also.
As a result, parents and children can have different implementations of the "same" private methods, depending on where you call them (e.g. parent or child class instance). Why? Because private methods are visible only for the class that defines them and the child class does not see the parent's private methods. If the child doesn't see the parent's private methods, the child can't override them. Scopes are different. In other words -- each class has a private set of private variables that no-one else has access to.
A sample demonstrating the percularities of private methods when extending classes:
<?php
abstract class base {
public function inherited() {
$this->overridden();
}
private function overridden() {
echo 'base';
}
}
class child extends base {
private function overridden() {
echo 'child';
}
}
$test = new child();
$test->inherited();
?>
Output will be "base".
If you want the inherited methods to use overridden functionality in extended classes but public sounds too loose, use protected. That's what it is for:)
A sample that works as intended:
<?php
abstract class base {
public function inherited() {
$this->overridden();
}
protected function overridden() {
echo 'base';
}
}
class child extends base {
protected function overridden() {
echo 'child';
}
}
$test = new child();
$test->inherited();
?>
Output will be "child".
WHEN do I use public, protected or private keyword? Here's the default behavior.
<?php
class Example
{
/* use PUBLIC on variables and functions when:
* 1. outside-code SHOULD access this property or function.
* 2. extending classes SHOULD inherit this property or function.
*/
public $var1;
public function someFunction_1() { }
/* use PROTECTED on variables and functions when:
* 1. outside-code SHOULD NOT access this property or function.
* 2. extending classes SHOULD inherit this property or function.
*/
protected $var2;
protected function someFunction_2() { }
/* use PRIVATE on variables and functions when:
* 1. outside-code SHOULD NOT access this property or function.
* 2. extending classes SHOULD NOT inherit this property or function.
*/
private $var3;
private function someFunction_3() { }
}
# these are the only valid calls outside-code can make on Example objects:
$obj1 = new Example(); // instantiate
$var1 = $obj1->var1; // get public data
$obj1->var1 = 35; // set public data
$obj1->someFunction_1(); // call public function
?>
Now try extending the class...
<?php
class Example_2 extends Example
{
// this class inherits the following properties and functions.
public $var1;
public function someFunction_1() { }
protected $var2;
protected function someFunction_2() { }
}
# these are the only valid calls outside-code can make on Example_2 objects:
$obj2 = new Example_2(); // instantiate
$var2 = $obj2->var1; // get public data
$obj2->var1 = 45; // set public data
$obj2->someFunction_1(); // call public function
?>
UNDERSTANDING PHP's OBJECT VISIBILITY
Sometimes it's good to see a list of many extended classes, one right after the other - just for the sole purpose of looking at their inherited members. Maybe this will help:
<?php
class MyClass_1{
public $pubVal = 'Hello World!';
protected $proVal = 'Hello FROM MyClass_1';
private $priVal = 'Hello TO MyClass_1';
public function __toString(){
return "MyClass_1[public=$this->pubVal, protected=$this->proVal, private=$this->priVal]";
}
}
class MyClass_2 extends MyClass_1{
public function __toString(){
return "MyClass_2[public=$this->pubVal, protected=$this->proVal, private=$this->priVal]";
}
}
class MyClass_3 extends MyClass_2{
private $priVal = 'Hello TO MyClass_3';
public function __toString(){
return "MyClass_3[public=$this->pubVal, protected=$this->proVal, private=$this->priVal]";
}
}
class MyClass_4 extends MyClass_3{
protected $proVal = 'Hello FROM MyClass_4';
public function __toString(){
return "MyClass_4[public=$this->pubVal, protected=$this->proVal, private=$this->priVal]";
}
}
class MyClass_5 extends MyClass_4{
public function __toString(){
return "MyClass_5[public=$this->pubVal, protected=$this->proVal, private=$this->priVal]";
}
}
class MyClass_6 extends MyClass_5{
private $priVal = 'Hello TO MyClass_6';
public function __toString(){
return "MyClass_6[public=$this->pubVal, protected=$this->proVal, private=$this->priVal]";
}
}
echo (new MyClass_1()) . '<br>';
echo (new MyClass_2()) . '<br>';
echo (new MyClass_3()) . '<br>';
echo (new MyClass_4()) . '<br>';
echo (new MyClass_5()) . '<br>';
echo (new MyClass_6()) . '<br>';
?>
The list of extended objects:
MyClass_1[public=Hello World!, protected=Hello FROM MyClass_1, private=Hello TO MyClass_1]
MyClass_2[public=Hello World!, protected=Hello FROM MyClass_1, private=]
MyClass_3[public=Hello World!, protected=Hello FROM MyClass_1, private=Hello TO MyClass_3]
MyClass_4[public=Hello World!, protected=Hello FROM MyClass_4, private=]
MyClass_5[public=Hello World!, protected=Hello FROM MyClass_4, private=]
MyClass_6[public=Hello World!, protected=Hello FROM MyClass_4, private=Hello TO MyClass_6]
Notice in the class definitions, I made absolutly no attempt to change protected members to private, etc. - that gets too confusing and is not necessary - though I did redeclare a few members with the same var name and visibility strength. One other noteworthy: the output for MyClass_2, there seems to be a private property with value of empty string. Here, $priVal was not inherited from MyClass_1 because it is private in MyClass_1, instead, because of PHP's relaxed syntax, it was actually created right there in MyClass2::__toString() method... not only that, it is not a private member either. Watch out for this kind of thing, as PHP can sometimes give confusing impressions.
Please note that if a class has a protected variable, a subclass cannot have the same variable redefined private (must be protected or weaker). It seemed to be logical for me as a subsubclass would not know if it could see it or not but even if you declare a subclass to be final the restriction remains.
Re: ference at super_delete_brose dot co dot uk
"If eval() is the answer, you’re almost certainly asking the wrong question."
<?php
eval('$result = $this->'.$var.';'); //wrong
$result = $this->$var; //right way
$var = "foo";
$this->var = "this will assign to member called 'var'.";
$this->$var = "this will assign to member called 'foo'.";
?>
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
?>
Sometimes you may wish to have all members of a class visible to other classes, but not editable - effectively read-only.
In this case defining them as public or protected is no good, but defining them as private is too strict and by convention requires you to write accessor functions.
Here is the lazy way, using one get function for accessing any of the variables:
<?php
class Foo {
private $a;
private $b;
private $c;
private $d;
private $e;
private $f;
public function __construct() {
$this->a = 'Value of $a';
$this->b = 'Value of $b';
$this->c = 'Value of $c';
$this->d = 'Value of $d';
$this->e = 'Value of $e';
$this->f = 'Value of $f';
}
/* Accessor for all class variables. */
public function get($what) {
$result = FALSE;
$vars = array_keys(get_class_vars('Foo'));
foreach ($vars as $var) {
if ($what == $var) {
eval('$result = $this->'.$var.';');
return $result;
}
}
return $result;
}
}
class Bar {
private $a;
public function __construct() {
$foo = new Foo();
var_dump($foo->get('a')); // results in: string(11) "Value of $a"
}
}
$bar = new Bar();
?>
If you always thought how can you use a private method in php4 classes then try the following within your class.
<?php
function private_func($func)
{
$this->file = __FILE__;
if (PHPVERS >= 43) {
$tmp = debug_backtrace();
for ($i=0; $i<count($tmp); ++$i) {
if (isset($tmp[$i]['function'][$func])) {
if ($this->file != $tmp[$i]['file']) {
trigger_error('Call to a private method '.__CLASS__.'::'.$func.' in '.$tmp[$i]['file'], E_USER_ERROR);
}
}
}
}
}
?>
Then inside the private function add:
<?php
function foo() {
$this->private_func(__FUNCTION__);
# your staff goes here
}
?>
A class A static public function can access to class A private function :
<?php
class A {
private function foo()
{
print("bar");
}
static public function bar($a)
{
$a->foo();
}
}
$a = new A();
A::bar($a);
?>
It's working.
This refers to previous notes on protected members being manipulated externally:
It is obvious that if you were to allow methods the option of replacing protected variables with external ones it will be possible, but there is no reason not to simply use a protected method to define these, or not to write the code to allow it. Just because it is possible doesn't mean it's a problem, it simply does not allow you to be lax on the security of the class.
Beware: Visibility works on a per-class-base and does not prevent instances of the same class accessing each others properties!
<?php
class Foo
{
private $bar;
public function debugBar(Foo $object)
{
// this does NOT violate visibility although $bar is private
echo $object->bar, "\n";
}
public function setBar($value)
{
// Neccessary method, for $bar is invisible outside the class
$this->bar = $value;
}
public function setForeignBar(Foo $object, $value)
{
// this does NOT violate visibility!
$object->bar = $value;
}
}
$a = new Foo();
$b = new Foo();
$a->setBar(1);
$b->setBar(2);
$a->debugBar($b); // 2
$b->debugBar($a); // 1
$a->setForeignBar($b, 3);
$b->setForeignBar($a, 4);
$a->debugBar($b); // 3
$b->debugBar($a); // 4
?>
Private visibility actually force members to be not inherited instead of limit its visibility. There is a small nuance that allows you to redeclare private member in child classes.
<?php
class A
{
private $prop = 'I am property of A!';
}
class B extends A
{
public $prop = 'I am property of B!';
}
$b = new B();
echo $b->prop; // "I am property of B!"
?>
A note about private members, the doc says "Private limits visibility only to the class that defines the item" this says that the following code works as espected:
<?php
class A {
private $_myPrivate="private";
public function showPrivate()
{
echo $this->_myPrivate."\n";
}
}
class B extends A {
public function show()
{
$this->showPrivate();
}
}
$obj=new B();
$obj->show(); // shows "private\n";
?>
this works cause A::showPrivate() is defined in the same class as $_myPrivate and has access to it.