Object variables

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

but as my example shows.. what happens if you extend the class and overload the getBalance() method? You won't get the balance.. infact, do anything in the child class and it won't affect the balance.

Here is a slight modification to show the exact problem with using private:

Code: Select all

<?php
class A
{
    private $var = 1;
    
    function setVar ($val)
    {
        $this->var = $val;
    }
    
    function getVar ()
    {
        return $this->var;
    }
}

class B extends A
{
    function setVar ($val)
    {
        $this->var = $val;
        echo "var set!\n";
    }
}

$a = new A;
$b = new B;

$a->setVar('a');
print $a->getVar()."\n";
$b->setVar('b');
print $b->getVar()."\n";
?>
Outputs:

Code: Select all

a
var set!
1
and yet overloading the getVar() method as well as the setVar method works as the above should work.. even if it is overloaded with the exact same:

Code: Select all

<?php
class A
{
    private $var = 1;
    
    function setVar ($val)
    {
        $this->var = $val;
    }
    
    function getVar ()
    {
        return $this->var;
    }
}

class B extends A
{
    function setVar ($val)
    {
        $this->var = $val;
        echo "var set!\n";
    }
    
    function getVar ()
    {
        return $this->var;
    }
}

$a = new A;
$b = new B;

$a->setVar('a');
print $a->getVar()."\n";
$b->setVar('b');
print $b->getVar()."\n";
?>
Outputs:

Code: Select all

a
var set!
b
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Jenk wrote:and yet overloading the getVar() method as well as the setVar method works as the above should work.. even if it is overloaded with the exact same:
Actually I don't think this is quite right. I believe that $var in A would not be visible to B, so $var in B would be a separate variable. Try this

Code: Select all

<?php
class A
{
    private $var = 1;
    
    function setVar ($val)
    {
        $this->var = $val;
    }
    
    function getVar ()
    {
        return $this->var;
    }

   function setVar2 ($val)
    {
        $this->var = $val;
    }
    
    function getVar2 ()
    {
        return $this->var;
    }
}

class B extends A
{
    function setVar ($val)
    {
        $this->var = $val;
        echo "var set!\n";
    }
    
    function getVar ()
    {
        return $this->var;
    }
}

$a = new A;
$b = new B;

$a->setVar('a');
print $a->getVar()."\n";
$b->setVar('b');
print $b->getVar()."\n";
print $b->getVar2()."\n";
$b->setVar2(2);
print $b->getVar2()."\n";
?>
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

small issue for both of you: you're trying to access a private variable in an extended class, which is going to net you a nice fat error. :)

Code: Select all

[feyd@home]>php -r "class a { private $a = 1; function getVar() { return $this->a; } } class b extends a { function getVar() { return $this->a; } } $t1 = new a(); $t2 = new b(); var_dump($t1->getVar(),$t2->getVar());"
PHP Notice:  Undefined property:  b::$a in Command line code on line 1

Notice: Undefined property:  b::$a in Command line code on line 1
int(1)
NULL

[feyd@home]>php -r "class a { protected $a = 1; function getVar() { return $this->a; } } class b extends a { function getVar() { return $this->a; } } $t1 = new a(); $t2 = new b(); var_dump($t1->getVar(),$t2->getVar());"
int(1)
int(1)

granted, calling setVar() in b will make a separate variable come into existance..
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

feyd wrote:small issue for both of you: you're trying to access a private variable in an extended class, which is going to net you a nice fat error. :)

granted, calling setVar() in b will make a separate variable come into existance..
Correct. Both of those things were what I was trying to demonstrate. Which means Private works as documented.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

and raises problems which I was trying to show..
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Jenk wrote:and raises problems which I was trying to show..
What are the problems?
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Post by Maugrim_The_Reaper »

Jenk wrote: but as my example shows.. what happens if you extend the class and overload the getBalance() method? You won't get the balance.. infact, do anything in the child class and it won't affect the balance.
Which is why the parent - due to overloading - just might be an abstract. Even if not an abstract and overloading is an ad-hoc decision you should probably recoognise the child requires access to the parent's private property and declare it as "protected" instead...

Unless I'm totally missing your problem?

I think a lot of this topic is going to head the way of "developer preference", i.e. you could argue the merits of both options for weeks without reaching a concensus on which is "better". Personally I use getters/setters, mainly because I find them more readable, they encapsulate, and hell...they just look neater...;)

Besides, I often do a bit more than just return a property value. Getter/Setters make it easier to add additional steps related to fetching or setting a property value. For example if storing a database table row in an object I might want to track which values are changed, so I can determine what values need updating, or if an update is even necessary...
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

Like you have also described, it's not a problem with the declaration itself, to further use the bankbalance example - what if the developer needs to overload the setter to, I dunno, verify the input is a float or validate the account number before setting etc.. thinking about it, it could be done like so:

Code: Select all

<?php

class BankAccount2 extends BankAccount
{
    function setBalance ($balance)
    {
        if (strval(floatval($balance)) === strval($balance)) {
            parent::setBalance($balance);
        } else {
            //error
        }
    }
}

?>
Actually, that looks like a good way of doing things.. but would that actually set the balance property of the object, or does parent::setBalance() call it statically?

This problem isn't really that evident in PHP, as to have the class you automatically have the source - though in another syntax it can be if the developer does not have the source to hand.
Last edited by Jenk on Mon Jan 16, 2006 4:57 pm, edited 1 time in total.
User avatar
raghavan20
DevNet Resident
Posts: 1451
Joined: Sat Jun 11, 2005 6:57 am
Location: London, UK
Contact:

Post by raghavan20 »

I see there is no security in using use getters() and setters() if you do not use access specifiers before them. I do think PHP 4 should not be held as example.....please use PHP 5.

Even if you use setters, any other class member function() or any statement should be able to access the setter function, you must prohibit access directly to the setter instead it should go through some other member function which first validates a request for updating balance is valid. Please use examples with access specifiers, private, protected and public.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

onion2k you say that it's not important now to do sanity checking on the properties... maybe it's not.

As the application this object structure resides in starts to grow I'd rather have that reassurance even when it's plain obvious... it's just good habit :) Another point I wanted to mention was that I'll often start coding things on a basic level... then as the app builds up when $obj->foo changes form I also need $obj->bar reflect that change. Using accessor methods can save you a lot of time in the long run even if you didn't predict the need in the first place.

Hockey, as for the comment about not using protected I agree with your pednantism when referring to properties in an object like that but when referring to class methods it works just the way it's intended... ;)
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

does it bug anyone else that methods/properties are referred to as member functions/variables respectively in the php manual?
Gambler
Forum Contributor
Posts: 246
Joined: Thu Dec 08, 2005 7:10 pm

Post by Gambler »

Yep. And it's not simply manual. Writing "private function" feels funny too.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Guys... even C++ books do that :D "member function"... what's the harm, it's just another terminology, it's not incorrect :) It's a function right? And it's a member of it's class.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

I'm a Java fan boy, therefore it's method and property for me :P

btw - if anyone else is curious about the result of my previous question RE: parent::get() -

Code: Select all

<?php      
    
class A
{
    private $a = 1;
    
    public function getA ($a)
    {
        $this->a = $a;
        return $this->a;
    }
}

class B extends A
{
    public function getA ()
    {
        return parent::getA('a');
    }
}

$b = new B;
echo $b->getA(); //outputs 'a'
      
?>
User avatar
raghavan20
DevNet Resident
Posts: 1451
Joined: Sat Jun 11, 2005 6:57 am
Location: London, UK
Contact:

[EDITED ]

Post by raghavan20 »

Gambler wrote:Writing "private function" feels funny too.
can you explain in detail what you are trying to say?


I am a fan of Java as well. Calling functions as member functions and variables as member variables is more meaningful. It is good to have properties for a class. This is a good concept in Java and I do not know whether this exists from C++. In Java beans, you have to mandatorily declare getters() and setters() for properties. Properties are something like characteristics of a class object logically. The use of getters() and setters() simplifies the use of beans in JSP. The following two statements allows to set and get a property and it makes use of getFirstName() and setFirstName() to set the value and get the value respectively.

<jsp:setProperty name = 'memberBean' property = 'firstName' value = 'Fred' />
<jsp:getProperty name = 'memberBean' property = 'firstName' />
Post Reply