AsyncTask
  • Package
  • Class
  • Todo

Packages

  • asynctask

Classes

  • AsyncTask
  1 <?php
  2 /**
  3  * AsyncTask
  4  *
  5  * Copyright (c) 2015, Dmitry Mamontov <d.slonyara@gmail.com>.
  6  * All rights reserved.
  7  *
  8  * Redistribution and use in source and binary forms, with or without
  9  * modification, are permitted provided that the following conditions
 10  * are met:
 11  *
 12  *   * Redistributions of source code must retain the above copyright
 13  *     notice, this list of conditions and the following disclaimer.
 14  *
 15  *   * Redistributions in binary form must reproduce the above copyright
 16  *     notice, this list of conditions and the following disclaimer in
 17  *     the documentation and/or other materials provided with the
 18  *     distribution.
 19  *
 20  *   * Neither the name of Dmitry Mamontov nor the names of his
 21  *     contributors may be used to endorse or promote products derived
 22  *     from this software without specific prior written permission.
 23  *
 24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 28  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 32  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 34  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 35  * POSSIBILITY OF SUCH DAMAGE.
 36  *
 37  * @package   asynctask
 38  * @author    Dmitry Mamontov <d.slonyara@gmail.com>
 39  * @copyright 2015 Dmitry Mamontov <d.slonyara@gmail.com>
 40  * @license   http://www.opensource.org/licenses/BSD-3-Clause  The BSD 3-Clause License
 41  * @since     File available since Release 1.0.3
 42  */
 43 
 44  /**
 45  * AsyncTask enables proper and easy use of the thread. This class allows to perform background operations and publish results on the thread without having to manipulate threads and/or handlers.
 46  *
 47  * @author    Dmitry Mamontov <d.slonyara@gmail.com>
 48  * @copyright 2015 Dmitry Mamontov <d.slonyara@gmail.com>
 49  * @license   http://www.opensource.org/licenses/BSD-3-Clause  The BSD 3-Clause License
 50  * @version   Release: 1.0.3
 51  * @link      https://github.com/dmamontov/asynctask
 52  * @since     Class available since Release 1.0.3
 53  * @todo      Planned to write a method publishProgress
 54  * @abstract
 55  */
 56 
 57 abstract class AsyncTask
 58 {
 59     /**
 60      * A numeric shared memory segment ID
 61      * @var integer
 62      * @static
 63      */
 64     private static $shmId;
 65 
 66     /**
 67      * The line number in which the object has been initialized
 68      * @var integer
 69      * @static
 70      */
 71     private $line;
 72 
 73     /**
 74      * Creates a new asynchronous task
 75      * @return void
 76      * @access public
 77      * @final
 78      */
 79     final public function __construct()
 80     {
 81         $error = "";
 82         if (version_compare(PHP_VERSION, '5.3.3', '<') || defined('HHVM_VERSION')) {
 83             $error .= "\n\e[0m\e[0;32mAsyncTask only officially supports PHP 5.3.3 and above,\e[0m";
 84         }
 85         if (!extension_loaded('pcntl')) {
 86             $error .= "\n\e[0m\e[0;32mAsyncTask uses the extension \"pcntl\",\e[0m";
 87         }
 88         if (!extension_loaded('posix')) {
 89             $error .= "\n\e[0m\e[0;32mAsyncTask uses the extension \"posix\",\e[0m";
 90         }
 91 
 92         if (mb_strlen($error) > 0) {
 93             throw new RuntimeException(
 94                $error . "\n\e[0m\e[0;32myou will most likely encounter problems with non-installed extensions,"
 95                       . "\n\e[0;31mupgrading is strongly recommended.\e[0m\n"
 96            );
 97         }
 98 
 99         $line = debug_backtrace();
100         $this->line = $line[0]['line'];
101 
102         self::$shmId = shm_attach((int) (ftok(__FILE__, 'A') . $this->line));
103         shm_put_var(self::$shmId, 11511697116117115, 'PENDING');
104         shm_put_var(self::$shmId, 112112105100, getmypid());
105     }
106 
107     /**
108      * Finish create an asynchronous task
109      * @return void
110      * @access public
111      * @final
112      */
113     final public function __destruct()
114     {
115         if (
116             @shm_has_var(self::$shmId, 112112105100) &&
117             shm_get_var(self::$shmId, 112112105100) == getmypid()
118         ) {
119             shm_remove(self::$shmId);
120         }
121     }
122 
123     /**
124      * Returns the variable with the given key
125      * @param string $key
126      * @return mixed
127      * @access public
128      * @static
129      * @final
130      */
131     final protected static function getProperty($key)
132     {
133         if (
134             in_array($key, array('shmId', 'pid', 'ppid', 'status')) === false &&
135             @shm_has_var(self::$shmId, self::getUid($key))
136         ) {
137             return shm_get_var(self::$shmId, self::getUid($key));
138         } else {
139             return false;
140         }
141     }
142 
143     /**
144      * Inserts or updates a variable with the given key
145      * @param string $key
146      * @param string $value
147      * @return boolean
148      * @access public
149      * @static
150      * @final
151      */
152     final protected static function setProperty($key, $value)
153     {
154         if (in_array($key, array('shmId', 'pid', 'ppid', 'status')) === false) {
155             shm_put_var(self::$shmId, self::getUid($key), $value);
156             return true;
157         } else {
158             return false;
159         }
160     }
161 
162     /**
163      * Returns a unique integer identifier for a given key
164      * @param string $key
165      * @return integer
166      * @access private
167      * @static
168      * @final
169      */
170     final private static function getUid($key)
171     {
172         $uid = '';
173         for ($char = 0; $char < strlen($key); $char++) {
174             $uid .= ord($key[ $char ]);
175         }
176 
177         return (int) $uid;
178     }
179 
180     /**
181      * Executes the task with the specified parameters
182      * @param mixed $parameters
183      * @return void
184      * @access public
185      * @final
186      */
187     final public function execute($parameters)
188     {
189         $pid = pcntl_fork();
190         if ($pid == -1) {
191             exit();
192         } elseif (!$pid) {
193             self::$shmId = shm_attach((int) (ftok(__FILE__, 'A') . $this->line));
194             shm_put_var(self::$shmId, 112105100, getmypid());
195             shm_put_var(self::$shmId, 11511697116117115, 'RUNNING');
196 
197             $this->onPreExecute();
198 
199             $result = $this->doInBackground($parameters);
200 
201             $this->onPostExecute($result);
202 
203             if (@shm_has_var(self::$shmId, 112105100)) {
204                 shm_put_var(self::$shmId, 112105100, null);
205                 shm_put_var(self::$shmId, 11511697116117115, 'FINISHED');
206             }
207             exit();
208         }
209     }
210 
211     /**
212      * Attempts to cancel execution of this task
213      * @return boolean
214      * @access public
215      * @final
216      */
217     final public function cancel()
218     {
219         if (
220             @shm_has_var(self::$shmId, 112105100) &&
221             is_null(shm_get_var(self::$shmId, 112105100)) !== null
222         ) {
223             $this->onCancelled();
224             posix_kill(shm_get_var(self::$shmId, 112105100), SIGKILL);
225             shm_put_var(self::$shmId, 112105100, null);
226             shm_put_var(self::$shmId, 11511697116117115, 'CANCELED');
227             return true;
228         } else {
229             return false;
230         }
231     }
232 
233     /**
234      * Returns the current status of this task
235      * @return string
236      * @access public
237      * @final
238      */
239     final public function getStatus()
240     {
241         return @shm_has_var(self::$shmId, 11511697116117115)
242                    ? shm_get_var(self::$shmId, 11511697116117115)
243                    : 'PENDING';
244     }
245 
246     /**
247      * Returns true if this task was cancelled before it completed normally
248      * @return boolean
249      * @access public
250      * @final
251      */
252     final public function isCancelled()
253     {
254         return @shm_has_var(self::$shmId, 11511697116117115) == 'CANCELED' ? true : false;
255     }
256 
257     /**
258      * Runs on the thread before doInBackground($parameters)
259      * @return void
260      * @access protected
261      */
262     protected function onPreExecute()
263     {
264     }
265 
266     /**
267      * Override this method to perform a computation on a background thread
268      * @param mixed $parameters
269      * @return mixed
270      * @access protected
271      * @abstract
272      */
273     abstract protected function doInBackground($parameters);
274 
275     /**
276      * Runs on the thread after doInBackground($parameters)
277      * @param mixed $result
278      * @return void
279      * @access protected
280      */
281     protected function onPostExecute($result)
282     {
283     }
284 
285     /**
286      * Runs on the thread after cancel()
287      * @return void
288      * @access protected
289      */
290     protected function onCancelled()
291     {
292     }
293 }
294 
AsyncTask API documentation generated by ApiGen