/** * Will generate the code used before the original function body * * @param bool $injectNeeded Determine if we have to use a try...catch block * @param FunctionDefinition $functionDefinition The function definition object * * @return string */ protected function generateBeforeCode($injectNeeded, FunctionDefinition $functionDefinition) { $suffix = PBC_ORIGINAL_FUNCTION_SUFFIX . str_replace('.', '', microtime(true)); $code = PBC_CONTRACT_CONTEXT . ' = \\TechDivision\\PBC\\ContractContext::open();'; // Invariant is not needed in private or static functions. // Also make sure that there is none in front of the constructor check if ($functionDefinition->getVisibility() !== 'private' && !$functionDefinition->getIsStatic() && $functionDefinition->getName() !== '__construct') { $code .= PBC_INVARIANT_PLACEHOLDER . PBC_PLACEHOLDER_CLOSE; } $code .= PBC_PRECONDITION_PLACEHOLDER . $functionDefinition->getName() . PBC_PLACEHOLDER_CLOSE . PBC_OLD_SETUP_PLACEHOLDER . $functionDefinition->getName() . PBC_PLACEHOLDER_CLOSE; // If we inject something we might need a try ... catch around the original call. if ($injectNeeded === true) { $code .= 'try {'; } // Build up the call to the original function. $code .= PBC_KEYWORD_RESULT . ' = ' . $functionDefinition->getHeader('call', $suffix) . ';'; // Finish the try ... catch and place the inject marker if ($injectNeeded === true) { $code .= '} catch (\\Exception $e) {}' . PBC_METHOD_INJECT_PLACEHOLDER . $functionDefinition->getName() . PBC_PLACEHOLDER_CLOSE; } // No just place all the other placeholder for other filters to come $code .= PBC_POSTCONDITION_PLACEHOLDER . $functionDefinition->getName() . PBC_PLACEHOLDER_CLOSE; // Invariant is not needed in private or static functions if ($functionDefinition->getVisibility() !== 'private' && !$functionDefinition->getIsStatic()) { $code .= PBC_INVARIANT_PLACEHOLDER . PBC_PLACEHOLDER_CLOSE; } $code .= 'if (' . PBC_CONTRACT_CONTEXT . ') {\\TechDivision\\PBC\\ContractContext::close();} return ' . PBC_KEYWORD_RESULT . ';}'; $code .= $functionDefinition->getHeader('definition', $suffix, true) . '{'; return $code; }
/** * This method will add all assertions any ancestral structures (parent classes, implemented interfaces) might have * to the passed class definition. * * @param \TechDivision\PBC\Entities\Definitions\FunctionDefinition $functionDefinition The function definition * we are working on * * @return void */ protected function addAncestralAssertions(FunctionDefinition $functionDefinition) { $dependencies = $this->currentDefinition->getDependencies(); foreach ($dependencies as $dependency) { // freshly set the dependency definition to avoid side effects $dependencyDefinition = null; $fileEntry = $this->structureMap->getEntry($dependency); if (!$fileEntry instanceof Structure) { // Continue, don't fail as we might have dependencies which are not under PBC surveillance continue; } // Get the needed parser $structureParserFactory = new StructureParserFactory(); $parser = $structureParserFactory->getInstance($fileEntry->getType(), $fileEntry->getPath(), $this->config, $this->structureMap, $this->structureDefinitionHierarchy); // Get the definition $dependencyDefinition = $parser->getDefinition($dependency, true); // Get the function definitions of the dependency structure $dependencyFunctionDefinitions = $dependencyDefinition->getFunctionDefinitions(); // If we have a method with the name of the current one we have to get the conditions as ancestrals if ($dependencyFunctionDefinitions->entryExists($functionDefinition->getName())) { // Get the definition $dependencyFunctionDefinition = $dependencyFunctionDefinitions->get($functionDefinition->getName()); // If the ancestral function uses the old keyword we have to do too if ($dependencyFunctionDefinition->getUsesOld() !== false) { $functionDefinition->usesOld = true; } // Get the conditions $functionDefinition->ancestralPreconditions = $dependencyFunctionDefinition->getAllPreconditions(true); $functionDefinition->ancestralPostconditions = $dependencyFunctionDefinition->getAllPostconditions(true); } } }
/** * Will change code to create an entry for the old object state. * * @param string $bucketData Payload of the currently * filtered bucket * @param \TechDivision\PBC\Entities\Definitions\FunctionDefinition $functionDefinition Currently handled function * * @throws \TechDivision\PBC\Exceptions\GeneratorException * * @return boolean */ private function injectOldCode(&$bucketData, FunctionDefinition &$functionDefinition) { // Do we even need to do anything? if ($functionDefinition->getUsesOld() !== true) { return false; } // If the function is static it should not use the pbcOld keyword as there is no state to the class! if ($functionDefinition->getIsStatic() === true) { throw new GeneratorException('Cannot clone class state in static method ' . $functionDefinition->getName()); } // Still here? Then inject the clone statement to preserve an instance of the object prior to our call. $bucketData = str_replace(PBC_OLD_SETUP_PLACEHOLDER . $functionDefinition->getName() . PBC_PLACEHOLDER_CLOSE, PBC_KEYWORD_OLD . ' = clone $this;', $bucketData); // Still here? We encountered no error then. return true; }