>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