Overview

Namespaces

  • None
  • PHP
  • picon

Classes

  • AbstractAjaxBehaviour
  • AbstractAssociatedMarkupSource
  • AbstractBehaviour
  • AbstractCallableOption
  • AbstractChoice
  • AbstractColumn
  • AbstractContextLoader
  • AbstractDatabaseDriver
  • AbstractInjectedDataProvider
  • AbstractJQueryBehaviour
  • AbstractJQueryUIBehaviour
  • AbstractLink
  • AbstractMarkupSource
  • AbstractMultipleChoice
  • AbstractOption
  • AbstractPageClassAuthorisationStrategy
  • AbstractRepeater
  • AbstractSingleChoice
  • AbstractTextComponent
  • AbstractToolbar
  • AbstractValidator
  • AjaxButton
  • AjaxEventBehaviour
  • AjaxFormComponentUpdateBehavior
  • AjaxFormSubmitBehavior
  • AjaxLink
  • AjaxRequestTarget
  • AllowAllAuthorisationStrategy
  • AnnotationRule
  • ApplicationConfigLoadListener
  • ApplicationContext
  • ApplicationContextLoadListener
  • ApplicationInitializer
  • ApplicationInitializerConfigLoadListenerCollection
  • ApplicationInitializerContextLoadListenerCollection
  • ApplicationProfile
  • Args
  • ArrayModel
  • ArrayOption
  • AttributeAppender
  • AttributeModifier
  • AutoContextLoader
  • AutoLoader
  • BasicModel
  • BooleanModel
  • BooleanOption
  • Border
  • BorderMarkupSourcingStratagy
  • BorderResolver
  • Button
  • CacheManager
  • CallbackAjaxCallDecorator
  • CallbackColumn
  • CallbackFunctionOption
  • CallbackOption
  • CallbackRowMapper
  • Check
  • CheckBox
  • CheckBoxGroup
  • CheckChoice
  • ChoiceRenderer
  • ClassNameRule
  • ClassNamespaceRule
  • ClassScanner
  • Comment
  • ComonDomainBase
  • Component
  • ComponentAfterRenderListenerCollection
  • ComponentAuthorisationListener
  • ComponentBeforeRenderListenerCollection
  • ComponentInitializationListenerCollection
  • ComponentInjector
  • ComponentInstantiationListenerCollection
  • ComponentRenderHeadListenerCollection
  • ComponentResolverHelper
  • ComponentTag
  • CompoundPropertyModel
  • Config
  • ConfigLoader
  • ContextLoaderFactory
  • DaoSupport
  • DataBaseTemplate
  • DataGridView
  • DataSource
  • DataSourceConfig
  • DataSourceFactory
  • DataSourceType
  • DataTable
  • DateField
  • DatePickerBehaviour
  • DefaultDataTable
  • DefaultJQueryUIBehaviour
  • DefaultMarkupSource
  • DefaultNotAuthorisedListener
  • DialogBehavior
  • DirectToPageComponentNotAuthorisedListener
  • DraggableBehaviour
  • DropDown
  • EmailAddressValidator
  • EmptyPanel
  • Enum
  • ExceptionPageRequestTarget
  • ExtendResolver
  • FeedbackMessage
  • FeedbackModel
  • FeedbackPanel
  • FileModel
  • FileUploadField
  • Form
  • FormComponent
  • FormComponentLabel
  • FormComponentPanel
  • FunctionOption
  • GridItem
  • GridView
  • HeaderContainer
  • HeaderPartContainer
  • HeaderResolver
  • HeaderResponse
  • HeaderToolbar
  • IdenticalValueValidator
  • Identifier
  • Injector
  • JQueryRenderHeadListener
  • JQueryUIRenderHeadListener
  • Label
  • LabeledMarkupContainer
  • Link
  • ListenerCollection
  • ListenerRequestResolver
  • ListenerRequestTarget
  • ListItem
  • ListMultiple
  • ListView
  • Localizer
  • ManualContextLoader
  • MarkupContainer
  • MarkupElement
  • MarkupLoader
  • MarkupParser
  • MarkupUtils
  • MaximumLengthValidator
  • MaximumValidator
  • MinimumLengthValidator
  • MinimumValidator
  • ModalWindow
  • MySqlDriver
  • MySqliDriver
  • NavigationLink
  • NavigationToolbar
  • Navigator
  • NumbericOption
  • NumericValidator
  • Objects
  • Options
  • PageInstanceRequestResolver
  • PageInstanceRequestTarget
  • PageMap
  • PageMapInitializationListenerCollection
  • PageNotFoundPage
  • PageNotFoundRequestTarget
  • PageRequestResolver
  • PageRequestTarget
  • PageRequestWithListenerTarget
  • PaginatingGridView
  • Panel
  • PanelMarkupSource
  • PanelResolver
  • PasswordField
  • PatternValidator
  • PiconApplication
  • PiconErrorHandler
  • PiconSerializer
  • PiconTag
  • PopupSettings
  • PropertyColumn
  • PropertyModel
  • PropertyOption
  • PropertyResolver
  • Radio
  • RadioChoice
  • RadioGroup
  • RangeLengthValidator
  • RangeValidator
  • RedirectRequestTarget
  • RepeatingView
  • RequestCycle
  • RequestResolverCollection
  • RequiredTextField
  • ResourceReference
  • ResourceRequestResolver
  • ResourceRequestTarget
  • SerializableClosure
  • SortableBehavior
  • StaticTabPanel
  • StringValidator
  • SubClassRule
  • Tab
  • TabCollection
  • TabPanel
  • TextArea
  • TextElement
  • TextField
  • TransparentMarkupContainer
  • ValidatableFormComponentWrapper
  • ValidationResponse
  • WebApplicationSecuritySettings
  • WebComponent
  • WebPage
  • WebRequest
  • WebResponse
  • WrappedCompoundModel
  • XMLDocument
  • XMLParser
  • XMLTag
  • XmlTagType

Interfaces

  • AjaxCallDecorator
  • ApplicationInitializerConfigLoadListener
  • ApplicationInitializerContextLoadListener
  • AuthorisationStrategy
  • Behaviour
  • BehaviourListener
  • CallDecoratorWrapper
  • ChoiceGroup
  • ClassScannerRule
  • Column
  • ComponentAfterRenderListener
  • ComponentAwareModel
  • ComponentBeforeRenderListener
  • ComponentInheritedModel
  • ComponentInitializationListener
  • ComponentInstantiationListener
  • ComponentNotAuthorisedListener
  • ComponentRenderHeadListener
  • ComponentResolver
  • CompoundModel
  • DatabaseDriver
  • DataBaseOperations
  • DataProvider
  • Detachable
  • Equalable
  • FormSubmitListener
  • FormSubmitter
  • Identifiable
  • InitializingBean
  • InjectOnWakeup
  • LinkListener
  • Listener
  • MarkupSource
  • Model
  • Pageable
  • PageMapInitializationListener
  • Request
  • RequestablePage
  • RequestResolver
  • RequestTarget
  • Response
  • RowMapper
  • Validatable
  • Validator
  • XmlElement

Exceptions

  • ConfigException
  • ConversionException
  • RestartRequestOnPageException
  • SQLException
  • UnAuthorisdeException
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Todo
  1: <?php
  2: 
  3: /**
  4:  * Picon Framework
  5:  * http://code.google.com/p/picon-framework/
  6:  *
  7:  * Copyright (C) 2011-2012 Martin Cassidy <martin.cassidy@webquub.com>
  8: 
  9:  * Picon Framework is free software: you can redistribute it and/or modify
 10:  * it under the terms of the GNU General Public License as published by
 11:  * the Free Software Foundation, either version 3 of the License, or
 12:  * (at your option) any later version.
 13: 
 14:  * Picon Framework is distributed in the hope that it will be useful,
 15:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 17:  *  General Public License for more details.
 18: 
 19:  * You should have received a copy of the GNU General Public License
 20:  * along with Picon Framework.  If not, see <http://www.gnu.org/licenses/>.
 21:  * */
 22: namespace picon;
 23: 
 24: /**
 25:  * A wrapper for closures enabling them to be serialized.
 26:  * IMPORTANT NOTE: This is highly experimental and needs further improvment and testing
 27:  * 
 28:  * A closure is serialized by deconstructing it into its parts, namely the string
 29:  * that represents its code and the paramaters it uses. The code is extracted
 30:  * with reflection and SplFileObject, the paramaters are extracted with reflection.
 31:  * 
 32:  * The code string and paramters are all that is serailized. On unserialize the code
 33:  * and paramters are used to reconstruct the closure using eval().
 34:  * 
 35:  * The usage of eval mean that SplFileObject can no longer be used on a reconstructed closure.
 36:  * However, this is solved by storing the previously extracted code for future use.
 37:  * 
 38:  * Any closure which is defined within a reconstructed closure can also not have SplFileObject
 39:  * used on it, as it was also defined by eval()'d code. To prevent this being a problem, all extracted
 40:  * code is processed so that an closures declared within have their own code isolated so that it may be
 41:  * used later when it is needed and would otherwise be un-obtainable with SplFileObject.
 42:  * 
 43:  * @todo imporove so that  all type hinting usage of classes within a closure don't need to be fully qualified
 44:  * @todo test in PHP 5.4.x
 45:  * @author Martin Cassidy
 46:  * @package utilities
 47:  */
 48: class SerializableClosure
 49: {
 50:     private $closure;
 51:     private $code;
 52:     private $arguments;
 53:     private $source;
 54:     private $reflection;
 55:     
 56:     public function __construct($closure, $code = null)
 57:     {
 58:         $this->validateClosure($closure);
 59:         $this->reflection = new \ReflectionFunction($closure);
 60:         
 61:         if($code==null)
 62:         {
 63:             $this->code = $this->fetchCode($this->reflection);
 64:             $this->prepareCode();
 65:         }
 66:         else
 67:         {
 68:             $this->code = base64_decode($code);
 69:         }
 70:         $this->arguments = $this->fetchUsedVariables($this->reflection, $this->code);
 71:         
 72:         if(method_exists($this->reflection, "getClosureThis"))
 73:         {
 74:             $this->source = $this->reflection->getClosureThis();
 75:         }
 76:     }
 77:     
 78:     /**
 79:      * Extract the code from the callback as a string
 80:      * @param ReflectionFunction The reflected function of the closure
 81:      * @return String The code the closure runs 
 82:      */
 83:     private function fetchCode(\ReflectionFunction $reflection)
 84:     {
 85:         $code = null;
 86:         $file = new \SplFileObject($reflection->getFileName());
 87:         $file->seek($reflection->getStartLine() - 1);
 88: 
 89:         $code = '';
 90:         while ($file->key() < $reflection->getEndLine())
 91:         {
 92:             $code .= $file->current();
 93:             $file->next();
 94:         }
 95: 
 96:         //@todo this assumes the function will be the only one on that line
 97:         $begin = strpos($code, 'function');
 98:         //@todo this assumes the } will be the only one on that line
 99:         $end = strrpos($code, '}');
100:         $code = substr($code, $begin, $end - $begin + 1);
101:         return $code;
102:     }
103:     
104:     /**
105:      * Performs string analysis to determin if anything needs to be altered
106:      * to allow the reconstructed closure to work correctly
107:      * @todo replace type hints with fq names
108:      */
109:     private function prepareCode()
110:     {
111:         $nested = array();
112:         $depth = 0;
113:         $closureSelf = false;
114:         $delcaration = false;
115:         $preparedClosure = "";
116:         $codeBlocks = token_get_all("<?php $this->code ?>");
117: 
118:         foreach($codeBlocks as $c)
119:         {
120:             $value = '';
121:             if(is_array($c))
122:             {
123:                 if($c[0]==T_FUNCTION)
124:                 {
125:                     if(!$closureSelf)
126:                     {
127:                         $closureSelf = true;
128:                     }
129:                     else
130:                     {
131:                         $delcaration = true;
132:                         $index = array_push($nested, array('depth' => $depth, 'content' => ''));
133:                         $preparedClosure .= 'new picon\SerializableClosure(';
134:                     }
135:                 }
136:                 $value = $c[1];
137:             }
138:             else
139:             {
140:                 $value = $c;
141:                 
142:                 if($c=="{")
143:                 {
144:                     $depth++;
145:                     $delcaration = false;
146:                 }
147:                 else if($c=="}")
148:                 {
149:                     $depth--;
150:                 }
151:             }
152:             $preparedClosure .= $value;
153:             
154:             foreach($nested as $index => $function)
155:             {
156:                 $nested[$index]['content'] .= $value;
157:                 if($function['depth']==$depth && !$delcaration)
158:                 {
159:                     $preparedClosure .= ', "'.base64_encode($nested[$index]['content']).'")';
160:                     unset($nested[$index]);
161:                 }
162:             }
163:         }
164:         $preparedClosure = substr($preparedClosure, 5, strlen($preparedClosure)-7);
165:         
166:         //function{1}\s*\({1}(\w*\s*&?\${1}\w+)*\){1}
167:         $this->code = $preparedClosure;
168:     } 
169:     
170:     /**
171:      * Extract bound variables
172:      * @param ReflectionFunction The reflected function of the closure
173:      * @param String The string of code the closure runs
174:      * @return Array The variable within the use() 
175:      */
176:     private function fetchUsedVariables(\ReflectionFunction $reflection, $code)
177:     {
178:         $use_index = stripos($code, 'use');
179:         if (!$use_index)
180:         {
181:             return array();
182:         }
183: 
184:         $begin = strpos($code, '(', $use_index) + 1;
185:         $end = strpos($code, ')', $begin);
186:         $vars = explode(',', substr($code, $begin, $end - $begin));
187: 
188:         $static_vars = $reflection->getStaticVariables();
189: 
190:         $used_vars = array();
191:         foreach ($vars as $var)
192:         {
193:             $var = preg_replace("/\\$|\\&/", "", trim($var));
194:             if(is_callable($static_vars[$var]) && !($static_vars[$var] instanceof SerializableClosure))
195:             {
196:                 $used_vars[$var] = new SerializableClosure($static_vars[$var]);
197:             }
198:             else
199:             {
200:                 $used_vars[$var] = $static_vars[$var];
201:             }
202:         }
203:         
204:         return $used_vars;
205:     }
206: 
207: 
208:     /**
209:      * Validates the closure
210:      * @param Closure The closure to validate
211:      */
212:     private function validateClosure($closure)
213:     {
214:         if (!isset($closure) || !($closure instanceof \Closure) || !is_callable($closure))
215:         {
216:             throw new \InvalidArgumentException("Closure was not valid");
217:         }
218:     }
219: 
220:     public function __sleep()
221:     {
222:         return(array('code', 'arguments'));
223:     }
224:     
225:     public function __wakeup()
226:     {
227:         extract($this->arguments);
228:         eval('$closure = '.$this->code.";");
229:         $this->closure = $closure;
230:         
231:         if(method_exists('Closure', 'bind'))
232:         {
233:             $this->closure = Closure::bind($this->closure, $this->source, get_class($this->source));
234:         }
235:         $this->reflection = new \ReflectionFunction($this->closure);
236:     }
237:     
238:     public function __invoke()
239:     {
240:         $args = func_get_args();
241:         return $this->reflection->invokeArgs($args);
242:     }
243:     
244:     public function getReflection()
245:     {
246:         return $this->reflection;
247:     }
248: }
249: ?>
250: 
Picon Framework API documentation generated by ApiGen 2.7.0