File indexing completed on 2025-01-19 05:21:27
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Search_Lucene 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 /** Zend_Search_Lucene_FSMAction */ 0023 // require_once 'Zend/Search/Lucene/FSMAction.php'; 0024 0025 /** 0026 * Abstract Finite State Machine 0027 * 0028 * Take a look on Wikipedia state machine description: http://en.wikipedia.org/wiki/Finite_state_machine 0029 * 0030 * Any type of Transducers (Moore machine or Mealy machine) also may be implemented by using this abstract FSM. 0031 * process() methods invokes a specified actions which may construct FSM output. 0032 * Actions may be also used to signal, that we have reached Accept State 0033 * 0034 * @category Zend 0035 * @package Zend_Search_Lucene 0036 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0037 * @license http://framework.zend.com/license/new-bsd New BSD License 0038 */ 0039 abstract class Zend_Search_Lucene_FSM 0040 { 0041 /** 0042 * Machine States alphabet 0043 * 0044 * @var array 0045 */ 0046 private $_states = array(); 0047 0048 /** 0049 * Current state 0050 * 0051 * @var integer|string 0052 */ 0053 private $_currentState = null; 0054 0055 /** 0056 * Input alphabet 0057 * 0058 * @var array 0059 */ 0060 private $_inputAphabet = array(); 0061 0062 /** 0063 * State transition table 0064 * 0065 * [sourceState][input] => targetState 0066 * 0067 * @var array 0068 */ 0069 private $_rules = array(); 0070 0071 /** 0072 * List of entry actions 0073 * Each action executes when entering the state 0074 * 0075 * [state] => action 0076 * 0077 * @var array 0078 */ 0079 private $_entryActions = array(); 0080 0081 /** 0082 * List of exit actions 0083 * Each action executes when exiting the state 0084 * 0085 * [state] => action 0086 * 0087 * @var array 0088 */ 0089 private $_exitActions = array(); 0090 0091 /** 0092 * List of input actions 0093 * Each action executes when entering the state 0094 * 0095 * [state][input] => action 0096 * 0097 * @var array 0098 */ 0099 private $_inputActions = array(); 0100 0101 /** 0102 * List of input actions 0103 * Each action executes when entering the state 0104 * 0105 * [state1][state2] => action 0106 * 0107 * @var array 0108 */ 0109 private $_transitionActions = array(); 0110 0111 /** 0112 * Finite State machine constructor 0113 * 0114 * $states is an array of integers or strings with a list of possible machine states 0115 * constructor treats fist list element as a sturt state (assignes it to $_current state). 0116 * It may be reassigned by setState() call. 0117 * States list may be empty and can be extended later by addState() or addStates() calls. 0118 * 0119 * $inputAphabet is the same as $states, but represents input alphabet 0120 * it also may be extended later by addInputSymbols() or addInputSymbol() calls. 0121 * 0122 * $rules parameter describes FSM transitions and has a structure: 0123 * array( array(sourseState, input, targetState[, inputAction]), 0124 * array(sourseState, input, targetState[, inputAction]), 0125 * array(sourseState, input, targetState[, inputAction]), 0126 * ... 0127 * ) 0128 * Rules also can be added later by addRules() and addRule() calls. 0129 * 0130 * FSM actions are very flexible and may be defined by addEntryAction(), addExitAction(), 0131 * addInputAction() and addTransitionAction() calls. 0132 * 0133 * @param array $states 0134 * @param array $inputAphabet 0135 * @param array $rules 0136 */ 0137 public function __construct($states = array(), $inputAphabet = array(), $rules = array()) 0138 { 0139 $this->addStates($states); 0140 $this->addInputSymbols($inputAphabet); 0141 $this->addRules($rules); 0142 } 0143 0144 /** 0145 * Add states to the state machine 0146 * 0147 * @param array $states 0148 */ 0149 public function addStates($states) 0150 { 0151 foreach ($states as $state) { 0152 $this->addState($state); 0153 } 0154 } 0155 0156 /** 0157 * Add state to the state machine 0158 * 0159 * @param integer|string $state 0160 */ 0161 public function addState($state) 0162 { 0163 $this->_states[$state] = $state; 0164 0165 if ($this->_currentState === null) { 0166 $this->_currentState = $state; 0167 } 0168 } 0169 0170 /** 0171 * Set FSM state. 0172 * No any action is invoked 0173 * 0174 * @param integer|string $state 0175 * @throws Zend_Search_Exception 0176 */ 0177 public function setState($state) 0178 { 0179 if (!isset($this->_states[$state])) { 0180 // require_once 'Zend/Search/Exception.php'; 0181 throw new Zend_Search_Exception('State \'' . $state . '\' is not on of the possible FSM states.'); 0182 } 0183 0184 $this->_currentState = $state; 0185 } 0186 0187 /** 0188 * Get FSM state. 0189 * 0190 * @return integer|string $state|null 0191 */ 0192 public function getState() 0193 { 0194 return $this->_currentState; 0195 } 0196 0197 /** 0198 * Add symbols to the input alphabet 0199 * 0200 * @param array $inputAphabet 0201 */ 0202 public function addInputSymbols($inputAphabet) 0203 { 0204 foreach ($inputAphabet as $inputSymbol) { 0205 $this->addInputSymbol($inputSymbol); 0206 } 0207 } 0208 0209 /** 0210 * Add symbol to the input alphabet 0211 * 0212 * @param integer|string $inputSymbol 0213 */ 0214 public function addInputSymbol($inputSymbol) 0215 { 0216 $this->_inputAphabet[$inputSymbol] = $inputSymbol; 0217 } 0218 0219 0220 /** 0221 * Add transition rules 0222 * 0223 * array structure: 0224 * array( array(sourseState, input, targetState[, inputAction]), 0225 * array(sourseState, input, targetState[, inputAction]), 0226 * array(sourseState, input, targetState[, inputAction]), 0227 * ... 0228 * ) 0229 * 0230 * @param array $rules 0231 */ 0232 public function addRules($rules) 0233 { 0234 foreach ($rules as $rule) { 0235 $this->addrule($rule[0], $rule[1], $rule[2], isset($rule[3])?$rule[3]:null); 0236 } 0237 } 0238 0239 /** 0240 * Add symbol to the input alphabet 0241 * 0242 * @param integer|string $sourceState 0243 * @param integer|string $input 0244 * @param integer|string $targetState 0245 * @param Zend_Search_Lucene_FSMAction|null $inputAction 0246 * @throws Zend_Search_Exception 0247 */ 0248 public function addRule($sourceState, $input, $targetState, $inputAction = null) 0249 { 0250 if (!isset($this->_states[$sourceState])) { 0251 // require_once 'Zend/Search/Exception.php'; 0252 throw new Zend_Search_Exception('Undefined source state (' . $sourceState . ').'); 0253 } 0254 if (!isset($this->_states[$targetState])) { 0255 // require_once 'Zend/Search/Exception.php'; 0256 throw new Zend_Search_Exception('Undefined target state (' . $targetState . ').'); 0257 } 0258 if (!isset($this->_inputAphabet[$input])) { 0259 // require_once 'Zend/Search/Exception.php'; 0260 throw new Zend_Search_Exception('Undefined input symbol (' . $input . ').'); 0261 } 0262 0263 if (!isset($this->_rules[$sourceState])) { 0264 $this->_rules[$sourceState] = array(); 0265 } 0266 if (isset($this->_rules[$sourceState][$input])) { 0267 // require_once 'Zend/Search/Exception.php'; 0268 throw new Zend_Search_Exception('Rule for {state,input} pair (' . $sourceState . ', '. $input . ') is already defined.'); 0269 } 0270 0271 $this->_rules[$sourceState][$input] = $targetState; 0272 0273 0274 if ($inputAction !== null) { 0275 $this->addInputAction($sourceState, $input, $inputAction); 0276 } 0277 } 0278 0279 0280 /** 0281 * Add state entry action. 0282 * Several entry actions are allowed. 0283 * Action execution order is defined by addEntryAction() calls 0284 * 0285 * @param integer|string $state 0286 * @param Zend_Search_Lucene_FSMAction $action 0287 */ 0288 public function addEntryAction($state, Zend_Search_Lucene_FSMAction $action) 0289 { 0290 if (!isset($this->_states[$state])) { 0291 // require_once 'Zend/Search/Exception.php'; 0292 throw new Zend_Search_Exception('Undefined state (' . $state. ').'); 0293 } 0294 0295 if (!isset($this->_entryActions[$state])) { 0296 $this->_entryActions[$state] = array(); 0297 } 0298 0299 $this->_entryActions[$state][] = $action; 0300 } 0301 0302 /** 0303 * Add state exit action. 0304 * Several exit actions are allowed. 0305 * Action execution order is defined by addEntryAction() calls 0306 * 0307 * @param integer|string $state 0308 * @param Zend_Search_Lucene_FSMAction $action 0309 */ 0310 public function addExitAction($state, Zend_Search_Lucene_FSMAction $action) 0311 { 0312 if (!isset($this->_states[$state])) { 0313 // require_once 'Zend/Search/Exception.php'; 0314 throw new Zend_Search_Exception('Undefined state (' . $state. ').'); 0315 } 0316 0317 if (!isset($this->_exitActions[$state])) { 0318 $this->_exitActions[$state] = array(); 0319 } 0320 0321 $this->_exitActions[$state][] = $action; 0322 } 0323 0324 /** 0325 * Add input action (defined by {state, input} pair). 0326 * Several input actions are allowed. 0327 * Action execution order is defined by addInputAction() calls 0328 * 0329 * @param integer|string $state 0330 * @param integer|string $input 0331 * @param Zend_Search_Lucene_FSMAction $action 0332 */ 0333 public function addInputAction($state, $inputSymbol, Zend_Search_Lucene_FSMAction $action) 0334 { 0335 if (!isset($this->_states[$state])) { 0336 // require_once 'Zend/Search/Exception.php'; 0337 throw new Zend_Search_Exception('Undefined state (' . $state. ').'); 0338 } 0339 if (!isset($this->_inputAphabet[$inputSymbol])) { 0340 // require_once 'Zend/Search/Exception.php'; 0341 throw new Zend_Search_Exception('Undefined input symbol (' . $inputSymbol. ').'); 0342 } 0343 0344 if (!isset($this->_inputActions[$state])) { 0345 $this->_inputActions[$state] = array(); 0346 } 0347 if (!isset($this->_inputActions[$state][$inputSymbol])) { 0348 $this->_inputActions[$state][$inputSymbol] = array(); 0349 } 0350 0351 $this->_inputActions[$state][$inputSymbol][] = $action; 0352 } 0353 0354 /** 0355 * Add transition action (defined by {state, input} pair). 0356 * Several transition actions are allowed. 0357 * Action execution order is defined by addTransitionAction() calls 0358 * 0359 * @param integer|string $sourceState 0360 * @param integer|string $targetState 0361 * @param Zend_Search_Lucene_FSMAction $action 0362 */ 0363 public function addTransitionAction($sourceState, $targetState, Zend_Search_Lucene_FSMAction $action) 0364 { 0365 if (!isset($this->_states[$sourceState])) { 0366 // require_once 'Zend/Search/Exception.php'; 0367 throw new Zend_Search_Exception('Undefined source state (' . $sourceState. ').'); 0368 } 0369 if (!isset($this->_states[$targetState])) { 0370 // require_once 'Zend/Search/Exception.php'; 0371 throw new Zend_Search_Exception('Undefined source state (' . $targetState. ').'); 0372 } 0373 0374 if (!isset($this->_transitionActions[$sourceState])) { 0375 $this->_transitionActions[$sourceState] = array(); 0376 } 0377 if (!isset($this->_transitionActions[$sourceState][$targetState])) { 0378 $this->_transitionActions[$sourceState][$targetState] = array(); 0379 } 0380 0381 $this->_transitionActions[$sourceState][$targetState][] = $action; 0382 } 0383 0384 0385 /** 0386 * Process an input 0387 * 0388 * @param mixed $input 0389 * @throws Zend_Search_Exception 0390 */ 0391 public function process($input) 0392 { 0393 if (!isset($this->_rules[$this->_currentState])) { 0394 // require_once 'Zend/Search/Exception.php'; 0395 throw new Zend_Search_Exception('There is no any rule for current state (' . $this->_currentState . ').'); 0396 } 0397 if (!isset($this->_rules[$this->_currentState][$input])) { 0398 // require_once 'Zend/Search/Exception.php'; 0399 throw new Zend_Search_Exception('There is no any rule for {current state, input} pair (' . $this->_currentState . ', ' . $input . ').'); 0400 } 0401 0402 $sourceState = $this->_currentState; 0403 $targetState = $this->_rules[$this->_currentState][$input]; 0404 0405 if ($sourceState != $targetState && isset($this->_exitActions[$sourceState])) { 0406 foreach ($this->_exitActions[$sourceState] as $action) { 0407 $action->doAction(); 0408 } 0409 } 0410 if (isset($this->_inputActions[$sourceState]) && 0411 isset($this->_inputActions[$sourceState][$input])) { 0412 foreach ($this->_inputActions[$sourceState][$input] as $action) { 0413 $action->doAction(); 0414 } 0415 } 0416 0417 0418 $this->_currentState = $targetState; 0419 0420 if (isset($this->_transitionActions[$sourceState]) && 0421 isset($this->_transitionActions[$sourceState][$targetState])) { 0422 foreach ($this->_transitionActions[$sourceState][$targetState] as $action) { 0423 $action->doAction(); 0424 } 0425 } 0426 if ($sourceState != $targetState && isset($this->_entryActions[$targetState])) { 0427 foreach ($this->_entryActions[$targetState] as $action) { 0428 $action->doAction(); 0429 } 0430 } 0431 } 0432 0433 public function reset() 0434 { 0435 if (count($this->_states) == 0) { 0436 // require_once 'Zend/Search/Exception.php'; 0437 throw new Zend_Search_Exception('There is no any state defined for FSM.'); 0438 } 0439 0440 $this->_currentState = $this->_states[0]; 0441 } 0442 } 0443