Re: Re: Why is access and visibility mixed up in PHP?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



>From: "Matthew Weier O'Phinney" <matthew@xxxxxxxxxx>

> * Terje Slettebø <tslettebo@xxxxxxxxxxxx>:
> > (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.

-- 
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php


[Index of Archives]     [PHP Home]     [Apache Users]     [PHP on Windows]     [Kernel Newbies]     [PHP Install]     [PHP Classes]     [Pear]     [Postgresql]     [Postgresql PHP]     [PHP on Windows]     [PHP Database Programming]     [PHP SOAP]

  Powered by Linux