/** * Will generate the skeleton code for the passed function definition. * Will result in a string resembling the following example: * * <FUNCTION_DOCBLOCK> * <FUNCTION_MODIFIERS> function <FUNCTION_NAME>(<FUNCTION_PARAMS>) * { * $dgStartLine = <FUNCTION_START_LINE>; * $dgEndLine = <FUNCTION_END_LINE>; * / DOPPELGAENGER_FUNCTION_BEGIN_PLACEHOLDER <FUNCTION_NAME> / * / DOPPELGAENGER_BEFORE_JOINPOINT <FUNCTION_NAME> / * $dgOngoingContract = \AppserverIo\Doppelgaenger\ContractContext::open(); * / DOPPELGAENGER_INVARIANT_PLACEHOLDER / * / DOPPELGAENGER_PRECONDITION_PLACEHOLDER <FUNCTION_NAME> / * / DOPPELGAENGER_OLD_SETUP_PLACEHOLDER <FUNCTION_NAME> / * $dgResult = null; * try { * / DOPPELGAENGER_AROUND_JOINPOINT <FUNCTION_NAME> / * * } catch (\Exception $dgThrownExceptionObject) { * / DOPPELGAENGER_AFTERTHROWING_JOINPOINT <FUNCTION_NAME> / * * // rethrow the exception * throw $dgThrownExceptionObject; * * } finally { * / DOPPELGAENGER_AFTER_JOINPOINT <FUNCTION_NAME> / * * } * / DOPPELGAENGER_POSTCONDITION_PLACEHOLDER <FUNCTION_NAME> / * / DOPPELGAENGER_INVARIANT_PLACEHOLDER / * if ($dgOngoingContract) { * \AppserverIo\Doppelgaenger\ContractContext::close(); * } / DOPPELGAENGER_AFTERRETURNING_JOINPOINT <FUNCTION_NAME> / * * return $dgResult; * } * * @param boolean $injectNeeded Determine if we have to use a try...catch block * @param FunctionDefinition $functionDefinition The function definition object * * @return string */ protected function generateSkeletonCode($injectNeeded, FunctionDefinition $functionDefinition) { // first of all: the docblock $code = ' ' . $functionDefinition->getDocBlock() . ' ' . $functionDefinition->getHeader('definition') . ' { ' . ReservedKeywords::START_LINE_VARIABLE . ' = ' . (int) $functionDefinition->getStartLine() . '; ' . ReservedKeywords::END_LINE_VARIABLE . ' = ' . (int) $functionDefinition->getEndLine() . '; ' . Placeholders::FUNCTION_BEGIN . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE . ' '; // right after: the "before" join-point $code .= Placeholders::BEFORE_JOINPOINT . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE . ' '; // open the contract context so we are able to avoid endless recursion $code .= ReservedKeywords::CONTRACT_CONTEXT . ' = \\AppserverIo\\Doppelgaenger\\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->isStatic() && $functionDefinition->getName() !== '__construct') { $code .= Placeholders::INVARIANT_CALL_START . ' '; } $code .= Placeholders::PRECONDITION . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE . ' ' . Placeholders::OLD_SETUP . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE . ' '; // we will wrap code execution in order to provide a "finally" and "after throwing" placeholder hook. // we will also predefine the result as NULL to avoid warnings $code .= ReservedKeywords::RESULT . ' = null; try { ' . Placeholders::AROUND_JOINPOINT . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE . ' '; // add the second part of the try/catch/finally block $code .= ' } catch (\\Exception ' . ReservedKeywords::THROWN_EXCEPTION_OBJECT . ') { ' . Placeholders::AFTERTHROWING_JOINPOINT . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE . ' // rethrow the exception throw ' . ReservedKeywords::THROWN_EXCEPTION_OBJECT . '; } finally { '; // if we have to inject additional code, we might do so here if ($injectNeeded === true) { $code .= Placeholders::METHOD_INJECT . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE; } // finish of the block $code .= ' ' . Placeholders::AFTER_JOINPOINT . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE . ' } '; // now just place all the other placeholder for other filters to come $code .= ' ' . Placeholders::POSTCONDITION . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE; // Invariant is not needed in private or static functions if ($functionDefinition->getVisibility() !== 'private' && !$functionDefinition->isStatic()) { $code .= ' ' . Placeholders::INVARIANT_CALL_END . ' '; } // close of the contract context $code .= 'if (' . ReservedKeywords::CONTRACT_CONTEXT . ') { \\AppserverIo\\Doppelgaenger\\ContractContext::close(); } '; // last of all: the "after returning" join-point and the final return from the proxy $code .= ' ' . Placeholders::AFTERRETURNING_JOINPOINT . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE . ' return ' . ReservedKeywords::RESULT . '; } '; return $code; }