1

I'm revising my OOPs concepts in PHP. I have a simple php code here for practising visibility.

When i declare $name as private in Big_Animal,

1)Why it doesn't throw an error when i try to assign a different value for $name from outside the class (ie. $lion->name="King")?

2)Why it doesn't throw an error when i try to reassign $name in Lion class (ie. $this->name="John").

I'm confused coz as per my knowledge, private properties can only be accessed within the class that defines the property.

The other thing i'm not clear about is protected properties. As per my understanding, protected properties can be accessed only within the class itself and its child classes. Can it be accessed by its grandchild classes?

Thank you.

<?php
abstract class Big_Animal{

 private $name="Mary";

  abstract public function Greet();

 public function Describe(){
    return "name: ".$this->name;
}

public function __set($name,$value){
    $this->name=$value;
}

public function __get($name){
    return $this->name;
}
}

class Lion extends Big_Animal{


public function Greet(){
    $this->name="John"; //no error for this
    return " roar!";
}



public function Describe(){
        return parent::Describe()." I'm a Lion!";
    }
}


$lion = new Lion();
$lion->name="King";  //no error for this
echo $lion->Describe();
echo $lion->Greet();

?>
vaanipala
  • 1,261
  • 7
  • 36
  • 63

4 Answers4

3

Because you are using magic method of __set()

__set() is run when writing data to inaccessible properties.

It is also possible to get the value by $lion->name because you also use __get().

xdazz
  • 158,678
  • 38
  • 247
  • 274
3
  1. Your magic method accessors (__set and __get) are public in the base, abstract class. They are the ones writing to the private data when you access the property directly. Try commenting out the magic methods and see. Then, the output is "name: Mary I'm a Lion! roar!".

  2. Add this as the first statement in Lion::Describe():

    echo "Lion's name: " . $this->name . "\n";

    As you can see, the output is now: "Lion's name: King". Both $this->name="John"; and $lion->name="King"; are modifying the public property on Lion class' object. It's unfortunate that you can have both public and private properties of the same name, but you can. They are simply different variables (in different scopes).

  3. Protected properties can be accessed from grandchildren. Most of your properties should be protected, unless you have a really strong reason to protect it (therefore using private). Public properties aren't used much in larger projects (depending on your style). I'd prefer to stick with explicit accessors. As a project progresses and becomes more complex, you'll be glad you chose to use accessors for each variable. I prefer to use a generator that will generate the scaffolding accessors for you. It saves a lot of time, cuts down on errors, and makes the creation of accessors a lot cheaper (and therefore more common).

UPDATE (a response to the comment below): 1) and 2) You're not getting errors because you're editing the Public variable in both of the instances that I listed in my 2) above. Try var_dump($lion):

object(Lion)#1 (2) {
  ["name":"Big_Animal":private]=>
  string(4) "Mary"
  ["name"]=>
  string(4) "John"
}

Also, if you explicitly add a private or protected member variable to the Lion class, you will get the error that you expect. I would agree with you that that's not very intuitive, but appears to be the current reality in PHP.

3) http://www.ibm.com/developerworks/opensource/library/os-php-7oohabits/ has an example of writing public accessors for private member variables (although, again, I'd recommend writing public accessors for protected member variables instead).

Homer6
  • 15,034
  • 11
  • 61
  • 81
  • I tried 1), ur right. I'm getting "name:Mary I'm a lion! roar!" but no errors. In 2) Yes, i'm getting "Lion's name: King". But, what do u mean by "It's unfortunate that you can have both public and private properties of the same name, but you can. They are simply different variables (in different scopes)." I dont see any public properties here. Regarding 3) i have no idea abt explicit accessors. I got to read up. Thanks. – vaanipala Aug 03 '12 at 07:18
  • @vaanipala: I've updated the answer with a response to these comments. Hope that helps. – Homer6 Aug 03 '12 at 15:57
1

To elaborate on my comment... You are using a function called __set, what this does is that every time you try to set a value on an unknown property on this class, this specific function is called.

In your function, you are always changing the private field name, into the value provided. Since this class has access to it's field, this is set.

Even if you wrote $lion->foo = "bar", the name would be set to bar, due to your function __set

Daniel MesSer
  • 1,191
  • 1
  • 7
  • 13
  • I tried what u said. I commented the __get and __set. The output is "name: Mary I'm a Lion! roar!". NO error although I have $lion = new Lion(); $lion->name="King"; $lion->foo="bar"; echo $lion->Describe(); echo $lion->Greet(); – vaanipala Aug 03 '12 at 07:09
  • @vaanipala: Php is a bit weird in many regards, check if you display_errors, check error log because that could be a silent error etc. Or you could have forgotten to save or something else happened. I'm uncertain wether "trying to set a property that doesnt exist" is classified as a show stopper or not. It might be that it is not. Welcome to the lovely world of php :) – Daniel MesSer Aug 03 '12 at 07:18
  • Ok, i've uncommented display_errors in php.ini, restarted apache web server and checked apache's error log fine. Still no errors. – vaanipala Aug 03 '12 at 08:15
-3

I think the answer for your question is here

Abstract methods cannot be private, because by definition they must be implemented by a derived class. If you don't want it to be public, it needs to be protected, which means that it can be seen by derived classes, but nobody else.

Community
  • 1
  • 1
Mihai Matei
  • 24,166
  • 5
  • 32
  • 50