Re: Re: Why is access and visibility mixed up in PHP?
| From: | Terje Slettebø | Date: | Sun, 23 Jan 2005 12:53:13 +0000 |
| Subject: | Re: Re: Why is access and visibility mixed up in PHP? | ||
| References: | 1 2 | Groups: | php.general |
| Request: | Send a blank email to php-general+get-207075@lists.php.net to get a copy of this message | ||
>From: "Matthew Weier O'Phinney" <matthew@garden.org>
> * Terje Slettebø <tslettebo@broadpark.no>:
> > (I've posted this to the PHP newsgroups, as well, but as many here might
not
> > read them, I post here, as well. I hope that's not considered
"overboard",
> > and if so, please let me know)
>
> The newsgroups are simply an NNTP interface to the mailing lists -- use
> one or the other; either way, it gets to the same place.
Ah, thanks. Sorry for the double-posts, then.
> <snip -- class with private method, subclass with private method>
> >
> > The above won't work, or at least not work as intended: The function
> > null_action() will only be visible in the class it's defined, and
therefore
> > the derived class version won't override the base class version. In
order to
> > get it to work, the access specifiers have to be changed to protected.
This
> > means that derived classes may also _call_ the function, something that
is
> > not desired. This means I can't enforce this design constraint of having
> > this function private.
> >
> > Why is it done like this?
>
> I'm not sure why the behaviour is as it is, but I do know that PHP
> developers were heavily influenced by Java when writing the new PHP5
> object model; I suspect your answers may lie there.
Yes, I think so, too, and I thought of that, as well. I think it does
something similar. I checked now: yep, it does the same there.
> One question I have to ask of you: why would you want the derived class
> to be able to know a method exists if it will not be able to call it?
> This seems to me to be... well, silly. Either the method is available to
> the class or it isn't and/or the method is available to an instantiated
> object or it isn't; visibility as being orthagonal to access just
> doesn't make a lot of sense to me. Perhaps you could make a case as to
> when this would be beneficial?
I realise that it may seem counter-intuitive or strange, but in this case it
actually makes sense: To take a practical example: A stopwatch FSM (example
from boost::fsm
(http://cvs.sourceforge.net/viewcvs.py/*checkout*/boost-sandbox/boost-sandbo
x/libs/fsm/doc/index.html?content-type=text%2Fplain&rev=1.31)). Here's a
complete, working example (except for the fsm class):
--- Start code ---
include_once("fsm.php");
// States (nested classes are not supported, so these must be at global
scope)
class active {}
class running extends active {}
class stopped extends active {}
class stopwatch_fsm extends fsm
{
public function stopwatch_fsm()
{
$this->fsm("stopped"); // Initial state
$this->add_transitions($this->transitions);
}
protected function start($from_state,$to_state)
{
echo "Start stopwatch<br>";
}
protected function stop($from_state,$to_state)
{
echo "Stop stopwatch<br>";
}
protected function reset($from_state,$to_state)
{
echo "Reset stopwatch<br>";
}
private $transitions=array(
// <signal>, <state>, <new state>, <action>
array("Start/stop button", "stopped",
"running","start"),
array("Start/stop button", "running", "stopped","stop"),
array("Reset button", "active", "stopped","reset"));
}
--- End code ---
To explain the above: The FSM stopwatch_fsm contains a state "active", with
two nested states "running" and "stopped". These are modelled as classes.
The transitions between the states are defined in the above array, each line
gives a signal/initial state/final state/action for a transition. For
example, if it's in the "stopped" state, and receives a "Start/stop button"
signal, it transitions to the "running" state, and calls the start() member
function. Same for the other two defined transitions.
Test program:
include_once("stopwatch_fsm.php");
$test=new stopwatch_fsm();
$test->process("Start/stop button");
$test->process("Start/stop button");
$test->process("Start/stop button");
$test->process("Reset button");
This will print:
Start stopwatch
Stop stopwatch
Start stopwatch
Reset stopwatch
The idea is that fsm will, upon doing state transitions, call the
appropriate action functions, as member functions (here, start/stop/reset),
so these have to be defined in the derived class. Interestingly, this
actually works even if start/stop/reset are _not_ defined in the base class,
fsm (!)
I seem to have talked myself into a corner. :) As these functions are not
defined in the base class, they are _not_ overridden in the derived class;
they are merely defined there. The example I had in the original posting was
a member function that _was_ defined in the base class, and overridden in
the derived class ("null_action"). This is the member function that gets
called, if no specific action function is provided in the transition table.
In _that_ example, the derived class would need to be able to override it,
but need not be able to call it (as it's called by the base class).
I hope this makes some kind of sense... :)
(By the way, besides pear::fsm, this is also inspired by the mentioned
boost::fsm, which also uses classes to model states)
> You might also want to take some of your questions to the php-dev list
> -- they seem to be more related to the internals of PHP than PHP usage.
Ah, I didn't know about that one. I didn't find it here:
http://www.php.net/mailing-lists.php How can I
subscribe to it?
Regards,
Terje
P.S. Why does replies to list posting go to the sender, rather than the
list, by default? Shouldn't reply-to be set to the list, as usual? I had to
manually edit the address, to make the reply go to the list.