Commit 37cb06e7 by Seldaek

* Some compiler fixes regarding custom plugins + a lot of tests for plugin types

git-svn-id: svn://dwoo.org/dwoo/trunk@139 0598d79b-80c4-4d41-97ba-ac86fbbd088b
parent 94616134
[2008-07-] 0.9.3 [2008-07-] 0.9.3
+ Plugins: Added the {a} block plugin to generate <a> tags
+ Syntax: Added the ";" token that allows to group multiple instructions in one + Syntax: Added the ";" token that allows to group multiple instructions in one
single template tag, example: {if $foo; "> $foo";$bar;/} is equal to: single template tag, example: {if $foo; "> $foo";$bar;/} is equal to:
{if $foo}> {$foo}{$bar}{/} - This also allow block operations such as: {if $foo}> {$foo}{$bar}{/} - This also allow block operations such as:
...@@ -7,17 +8,17 @@ ...@@ -7,17 +8,17 @@
self-closed just like XML tags (e.g. {a "http://url.com" /} ). Be careful not self-closed just like XML tags (e.g. {a "http://url.com" /} ). Be careful not
to close a non-block plugin like that however, since it will close it's to close a non-block plugin like that however, since it will close it's
parent block parent block
+ Plugins: Added the {a} block plugin to generate <a> tags + Syntax: Static methods can be called using {Class::method()}
+ Syntax: It is now possible to use a plugin's result as an object and call
a method or read a property from it, i.e. {fetchObject()->doStuff()}
+ API: Added Dwoo_Plugin::paramsToAttributes() utility function to help + API: Added Dwoo_Plugin::paramsToAttributes() utility function to help
with the creation of compilable xml/html-related plugins with the creation of compilable xml/html-related plugins
+ Syntax: Static methods can be called using {Class::method()}
+ Compiler supports method calls into a method call's parameters
+ API: Added Dwoo->setPluginProxy() and Dwoo_IPluginProxy that allow you to + API: Added Dwoo->setPluginProxy() and Dwoo_IPluginProxy that allow you to
hook into the compiler's plugin subsystem to provide your own plugin calls. hook into the compiler's plugin subsystem to provide your own plugin calls.
Thanks to Denis Arh for the patch Thanks to Denis Arh for the patch
=> http://forum.dwoo.org/viewtopic.php?id=70 => http://forum.dwoo.org/viewtopic.php?id=70
+ Syntax: It is now possible to use a plugin's result as an object and call + API: Dwoo->addPlugin() has a third parameter to mark a plugin as compilable
a method or read a property from it, i.e. {fetchObject()->doStuff()} + Compiler supports method calls into a method call's parameters
* Dwoo_Compiler::implode_r is now public/static so it can be used in other * Dwoo_Compiler::implode_r is now public/static so it can be used in other
places such as plugin proxies places such as plugin proxies
* Syntax: Math expressions in strings are now only allowed when the entire * Syntax: Math expressions in strings are now only allowed when the entire
...@@ -32,6 +33,7 @@ ...@@ -32,6 +33,7 @@
=> http://forum.dwoo.org/viewtopic.php?id=70 => http://forum.dwoo.org/viewtopic.php?id=70
* Fixed a compileId auto-generation creating conflicts * Fixed a compileId auto-generation creating conflicts
* Include allows paths going in upper levels now such as : "../foo.html" * Include allows paths going in upper levels now such as : "../foo.html"
* Some compiler fixes regarding custom plugins
[2008-06-28] 0.9.2 [2008-06-28] 0.9.2
! BC Break: Renamed the {strip} modifier/function to {whitespace}, this does ! BC Break: Renamed the {strip} modifier/function to {whitespace}, this does
......
...@@ -503,23 +503,25 @@ class Dwoo ...@@ -503,23 +503,25 @@ class Dwoo
* @param callback $callback the plugin callback, either a function name, * @param callback $callback the plugin callback, either a function name,
* a class name or an array containing an object * a class name or an array containing an object
* or class name and a method name * or class name and a method name
* @param bool $compilable if set to true, the plugin is assumed to be compilable
*/ */
public function addPlugin($name, $callback) public function addPlugin($name, $callback, $compilable = false)
{ {
$compilable = $compilable ? self::COMPILABLE_PLUGIN : 0;
if (is_array($callback)) { if (is_array($callback)) {
if (is_subclass_of(is_object($callback[0]) ? get_class($callback[0]) : $callback[0], 'Dwoo_Block_Plugin')) { if (is_subclass_of(is_object($callback[0]) ? get_class($callback[0]) : $callback[0], 'Dwoo_Block_Plugin')) {
$this->plugins[$name] = array('type'=>self::BLOCK_PLUGIN, 'callback'=>$callback, 'class'=>(is_object($callback[0]) ? get_class($callback[0]) : $callback[0])); $this->plugins[$name] = array('type'=>self::BLOCK_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>(is_object($callback[0]) ? get_class($callback[0]) : $callback[0]));
} else { } else {
$this->plugins[$name] = array('type'=>self::CLASS_PLUGIN, 'callback'=>$callback, 'class'=>(is_object($callback[0]) ? get_class($callback[0]) : $callback[0]), 'function'=>$callback[1]); $this->plugins[$name] = array('type'=>self::CLASS_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>(is_object($callback[0]) ? get_class($callback[0]) : $callback[0]), 'function'=>$callback[1]);
} }
} elseif (class_exists($callback, false)) { } elseif (class_exists($callback, false)) {
if (is_subclass_of($callback, 'Dwoo_Block_Plugin')) { if (is_subclass_of($callback, 'Dwoo_Block_Plugin')) {
$this->plugins[$name] = array('type'=>self::BLOCK_PLUGIN, 'callback'=>$callback, 'class'=>$callback); $this->plugins[$name] = array('type'=>self::BLOCK_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>$callback);
} else { } else {
$this->plugins[$name] = array('type'=>self::CLASS_PLUGIN, 'callback'=>$callback, 'class'=>$callback, 'function'=>'process'); $this->plugins[$name] = array('type'=>self::CLASS_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>$callback, 'function'=>'process');
} }
} elseif (function_exists($callback)) { } elseif (function_exists($callback)) {
$this->plugins[$name] = array('type'=>self::FUNC_PLUGIN, 'callback'=>$callback); $this->plugins[$name] = array('type'=>self::FUNC_PLUGIN | $compilable, 'callback'=>$callback);
} else { } else {
throw new Dwoo_Exception('Callback could not be processed correctly, please check that the function/class you used exists'); throw new Dwoo_Exception('Callback could not be processed correctly, please check that the function/class you used exists');
} }
......
...@@ -1426,12 +1426,16 @@ class Dwoo_Compiler implements Dwoo_ICompiler ...@@ -1426,12 +1426,16 @@ class Dwoo_Compiler implements Dwoo_ICompiler
} }
} elseif ($pluginType & Dwoo::FUNC_PLUGIN) { } elseif ($pluginType & Dwoo::FUNC_PLUGIN) {
if ($pluginType & Dwoo::COMPILABLE_PLUGIN) { if ($pluginType & Dwoo::COMPILABLE_PLUGIN) {
$funcCompiler = 'Dwoo_Plugin_'.$func.'_compile'; if ($pluginType & Dwoo::CUSTOM_PLUGIN) {
$funcCompiler = $this->customPlugins[$func]['callback'];
} else {
$funcCompiler = 'Dwoo_Plugin_'.$func.'_compile';
}
array_unshift($params, $this); array_unshift($params, $this);
$output = call_user_func_array($funcCompiler, $params); $output = call_user_func_array($funcCompiler, $params);
} else { } else {
array_unshift($params, '$this'); array_unshift($params, '$this');
$params = $this->implode_r($params); $params = self::implode_r($params);
if ($pluginType & Dwoo::CUSTOM_PLUGIN) { if ($pluginType & Dwoo::CUSTOM_PLUGIN) {
$callback = $this->customPlugins[$func]['callback']; $callback = $this->customPlugins[$func]['callback'];
...@@ -1442,14 +1446,33 @@ class Dwoo_Compiler implements Dwoo_ICompiler ...@@ -1442,14 +1446,33 @@ class Dwoo_Compiler implements Dwoo_ICompiler
} }
} elseif ($pluginType & Dwoo::CLASS_PLUGIN) { } elseif ($pluginType & Dwoo::CLASS_PLUGIN) {
if ($pluginType & Dwoo::COMPILABLE_PLUGIN) { if ($pluginType & Dwoo::COMPILABLE_PLUGIN) {
$funcCompiler = array('Dwoo_Plugin_'.$func, 'compile'); if ($pluginType & Dwoo::CUSTOM_PLUGIN) {
array_unshift($params, $this); $callback = $this->customPlugins[$func]['callback'];
if (!is_array($callback)) {
if (!method_exists($callback, 'compile')) {
throw new Dwoo_Exception('Custom plugin '.$func.' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
}
if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) {
$funcCompiler = array($callback, 'compile');
} else {
$funcCompiler = array(new $callback, 'compile');
}
} else {
$funcCompiler = $callback;
}
} else {
$funcCompiler = array('Dwoo_Plugin_'.$func, 'compile');
array_unshift($params, $this);
}
$output = call_user_func_array($funcCompiler, $params); $output = call_user_func_array($funcCompiler, $params);
} else { } else {
$params = $this->implode_r($params); $params = self::implode_r($params);
if ($pluginType & Dwoo::CUSTOM_PLUGIN) { if ($pluginType & Dwoo::CUSTOM_PLUGIN) {
$callback = $this->customPlugins[$func]['callback']; $callback = $this->customPlugins[$func]['callback'];
if (!is_array($callback)) { if (!is_array($callback)) {
if (!method_exists($callback, 'process')) {
throw new Dwoo_Exception('Custom plugin '.$func.' must implement the "process" method to be usable, or you should provide a full callback to the method to use');
}
if (($ref = new ReflectionMethod($callback, 'process')) && $ref->isStatic()) { if (($ref = new ReflectionMethod($callback, 'process')) && $ref->isStatic()) {
$output = 'call_user_func(array(\''.$callback.'\', \'process\'), '.$params.')'; $output = 'call_user_func(array(\''.$callback.'\', \'process\'), '.$params.')';
} else { } else {
...@@ -1476,7 +1499,7 @@ class Dwoo_Compiler implements Dwoo_ICompiler ...@@ -1476,7 +1499,7 @@ class Dwoo_Compiler implements Dwoo_ICompiler
$output = call_user_func(array($this->dwoo->getPluginProxy(), $func)); $output = call_user_func(array($this->dwoo->getPluginProxy(), $func));
} }
} elseif ($pluginType & Dwoo::SMARTY_FUNCTION) { } elseif ($pluginType & Dwoo::SMARTY_FUNCTION) {
$params = $this->implode_r($params['*'], true); $params = self::implode_r($params['*'], true);
if ($pluginType & Dwoo::CUSTOM_PLUGIN) { if ($pluginType & Dwoo::CUSTOM_PLUGIN) {
$callback = $this->customPlugins[$func]['callback']; $callback = $this->customPlugins[$func]['callback'];
...@@ -2356,7 +2379,7 @@ class Dwoo_Compiler implements Dwoo_ICompiler ...@@ -2356,7 +2379,7 @@ class Dwoo_Compiler implements Dwoo_ICompiler
$params = $params['*'][0]; $params = $params['*'][0];
$params = $this->implode_r($params); $params = self::implode_r($params);
if ($mapped) { if ($mapped) {
$output = '$this->arrayMap(\''.$func.'\', array('.$params.'))'; $output = '$this->arrayMap(\''.$func.'\', array('.$params.'))';
...@@ -2371,7 +2394,7 @@ class Dwoo_Compiler implements Dwoo_ICompiler ...@@ -2371,7 +2394,7 @@ class Dwoo_Compiler implements Dwoo_ICompiler
$params = $this->mapParams($params, null, $state); $params = $this->mapParams($params, null, $state);
$params = $params['*'][0]; $params = $params['*'][0];
$params = $this->implode_r($params); $params = self::implode_r($params);
if ($pluginType & Dwoo::CUSTOM_PLUGIN) { if ($pluginType & Dwoo::CUSTOM_PLUGIN) {
$callback = $this->customPlugins[$func]['callback']; $callback = $this->customPlugins[$func]['callback'];
...@@ -2415,13 +2438,17 @@ class Dwoo_Compiler implements Dwoo_ICompiler ...@@ -2415,13 +2438,17 @@ class Dwoo_Compiler implements Dwoo_ICompiler
if ($mapped) { if ($mapped) {
throw new Dwoo_Compilation_Exception($this, 'The @ operator can not be used on compiled plugins.'); throw new Dwoo_Compilation_Exception($this, 'The @ operator can not be used on compiled plugins.');
} }
$funcCompiler = 'Dwoo_Plugin_'.$func.'_compile'; if ($pluginType & Dwoo::CUSTOM_PLUGIN) {
$funcCompiler = $this->customPlugins[$func]['callback'];
} else {
$funcCompiler = 'Dwoo_Plugin_'.$func.'_compile';
}
array_unshift($params, $this); array_unshift($params, $this);
$output = call_user_func_array($funcCompiler, $params); $output = call_user_func_array($funcCompiler, $params);
} else { } else {
array_unshift($params, '$this'); array_unshift($params, '$this');
$params = $this->implode_r($params); $params = self::implode_r($params);
if ($mapped) { if ($mapped) {
$output = '$this->arrayMap(\''.$pluginName.'\', array('.$params.'))'; $output = '$this->arrayMap(\''.$pluginName.'\', array('.$params.'))';
} else { } else {
...@@ -2433,11 +2460,27 @@ class Dwoo_Compiler implements Dwoo_ICompiler ...@@ -2433,11 +2460,27 @@ class Dwoo_Compiler implements Dwoo_ICompiler
if ($mapped) { if ($mapped) {
throw new Dwoo_Compilation_Exception($this, 'The @ operator can not be used on compiled plugins.'); throw new Dwoo_Compilation_Exception($this, 'The @ operator can not be used on compiled plugins.');
} }
$funcCompiler = array('Dwoo_Plugin_'.$func, 'compile'); if ($pluginType & Dwoo::CUSTOM_PLUGIN) {
array_unshift($params, $this); $callback = $this->customPlugins[$func]['callback'];
if (!is_array($callback)) {
if (!method_exists($callback, 'compile')) {
throw new Dwoo_Exception('Custom plugin '.$func.' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
}
if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) {
$funcCompiler = array($callback, 'compile');
} else {
$funcCompiler = array(new $callback, 'compile');
}
} else {
$funcCompiler = $callback;
}
} else {
$funcCompiler = array('Dwoo_Plugin_'.$func, 'compile');
array_unshift($params, $this);
}
$output = call_user_func_array($funcCompiler, $params); $output = call_user_func_array($funcCompiler, $params);
} else { } else {
$params = $this->implode_r($params); $params = self::implode_r($params);
if ($pluginType & Dwoo::CUSTOM_PLUGIN) { if ($pluginType & Dwoo::CUSTOM_PLUGIN) {
if (is_object($callback[0])) { if (is_object($callback[0])) {
......
...@@ -29,6 +29,7 @@ class DwooTests extends PHPUnit_Framework_TestSuite { ...@@ -29,6 +29,7 @@ class DwooTests extends PHPUnit_Framework_TestSuite {
} }
protected function tearDown() { protected function tearDown() {
$this->clearDir(TEST_DIRECTORY.'/temp/cache', true);
$this->clearDir(TEST_DIRECTORY.'/temp/compiled', true); $this->clearDir(TEST_DIRECTORY.'/temp/compiled', true);
} }
......
<?php
require_once 'Dwoo/Compiler.php';
class PluginTypesTests extends PHPUnit_Framework_TestCase
{
protected $compiler;
protected $dwoo;
public function __construct()
{
// extend this class and override this in your constructor to test a modded compiler
$this->compiler = new Dwoo_Compiler();
$this->dwoo = new Dwoo(DWOO_COMPILE_DIR, DWOO_CACHE_DIR);
}
// Functions - Dwoo style
public function testCompilableFunctionPlugin()
{
$tpl = new Dwoo_Template_String('{CompilableFunctionPlugin 4 5}');
$tpl->forceCompilation();
$this->assertEquals('20', $this->dwoo->get($tpl, array(), $this->compiler));
}
public function testCompilableFunctionPluginAsModifier()
{
$tpl = new Dwoo_Template_String('{$foo=4}{$foo|CompilableFunctionPlugin:5}');
$tpl->forceCompilation();
$this->assertEquals('20', $this->dwoo->get($tpl, array(), $this->compiler));
}
public function testFunctionPlugin()
{
$tpl = new Dwoo_Template_String('{FunctionPlugin 4 5}');
$tpl->forceCompilation();
$this->assertEquals('20', $this->dwoo->get($tpl, array(), $this->compiler));
}
public function testFunctionPluginAsModifier()
{
$tpl = new Dwoo_Template_String('{$foo=4}{$foo|FunctionPlugin:5}');
$tpl->forceCompilation();
$this->assertEquals('20', $this->dwoo->get($tpl, array(), $this->compiler));
}
// Classes - Dwoo style
public function testCompilableClassPlugin()
{
$tpl = new Dwoo_Template_String('{CompilableClassPlugin 4 5}');
$tpl->forceCompilation();
$this->assertEquals('20', $this->dwoo->get($tpl, array(), $this->compiler));
}
public function testCompilableClassPluginAsModifier()
{
$tpl = new Dwoo_Template_String('{$foo=4}{$foo|CompilableClassPlugin:5}');
$tpl->forceCompilation();
$this->assertEquals('20', $this->dwoo->get($tpl, array(), $this->compiler));
}
public function testClassPlugin()
{
$tpl = new Dwoo_Template_String('{ClassPlugin 4 5}');
$tpl->forceCompilation();
$this->assertEquals('20', $this->dwoo->get($tpl, array(), $this->compiler));
}
public function testClassPluginAsModifier()
{
$tpl = new Dwoo_Template_String('{$foo=4}{$foo|ClassPlugin:5}');
$tpl->forceCompilation();
$this->assertEquals('20', $this->dwoo->get($tpl, array(), $this->compiler));
}
// Functions - Custom style
public function testCustomCompilableFunctionPlugin()
{
$dwoo = new Dwoo();
$dwoo->addPlugin('CustomCompilableFunctionPlugin', 'custom_compilable_plugin', true);
$tpl = new Dwoo_Template_String('{CustomCompilableFunctionPlugin 4 5}');
$tpl->forceCompilation();
$this->assertEquals('20', $dwoo->get($tpl, array(), $this->compiler));
}
public function testCustomCompilableFunctionPluginAsModifier()
{
$dwoo = new Dwoo();
$dwoo->addPlugin('CustomCompilableFunctionPlugin', 'custom_compilable_plugin', true);
$tpl = new Dwoo_Template_String('{$foo=4}{$foo|CustomCompilableFunctionPlugin:5}');
$tpl->forceCompilation();
$this->assertEquals('20', $dwoo->get($tpl, array(), $this->compiler));
}
public function testCustomFunctionPlugin()
{
$dwoo = new Dwoo();
$dwoo->addPlugin('CustomFunctionPlugin', 'custom_plugin');
$tpl = new Dwoo_Template_String('{CustomFunctionPlugin 4 5}');
$tpl->forceCompilation();
$this->assertEquals('20', $dwoo->get($tpl, array(), $this->compiler));
}
public function testCustomFunctionPluginAsModifier()
{
$dwoo = new Dwoo();
$dwoo->addPlugin('CustomFunctionPlugin', 'custom_plugin');
$tpl = new Dwoo_Template_String('{$foo=4}{$foo|CustomFunctionPlugin:5}');
$tpl->forceCompilation();
$this->assertEquals('20', $dwoo->get($tpl, array(), $this->compiler));
}
// Classes - Custom style - Static
public function testCustomCompilableClassPlugin()
{
$dwoo = new Dwoo();
$dwoo->addPlugin('CustomCompilableClassPlugin', array('custom_compilable_class_plugin', 'call'), true);
$tpl = new Dwoo_Template_String('{CustomCompilableClassPlugin 4 5}');
$tpl->forceCompilation();
$this->assertEquals('20', $dwoo->get($tpl, array(), $this->compiler));
}
public function testCustomCompilableClassPluginAsModifier()
{
$dwoo = new Dwoo();
$dwoo->addPlugin('CustomCompilableClassPlugin', array('custom_compilable_class_plugin', 'call'), true);
$tpl = new Dwoo_Template_String('{$foo=4}{$foo|CustomCompilableClassPlugin:5}');
$tpl->forceCompilation();
$this->assertEquals('20', $dwoo->get($tpl, array(), $this->compiler));
}
public function testCustomClassPlugin()
{
$dwoo = new Dwoo();
$dwoo->addPlugin('CustomClassPlugin', array('custom_class_plugin', 'call'));
$tpl = new Dwoo_Template_String('{CustomClassPlugin 4 5}');
$tpl->forceCompilation();
$this->assertEquals('20', $dwoo->get($tpl, array(), $this->compiler));
}
public function testCustomClassPluginAsModifier()
{
$dwoo = new Dwoo();
$dwoo->addPlugin('CustomClassPlugin', array('custom_class_plugin', 'call'));
$tpl = new Dwoo_Template_String('{$foo=4}{$foo|CustomClassPlugin:5}');
$tpl->forceCompilation();
$this->assertEquals('20', $dwoo->get($tpl, array(), $this->compiler));
}
// Classes - Custom style - Instance
public function testCustomCompilableClassPluginInstance()
{
$dwoo = new Dwoo();
$dwoo->addPlugin('CustomCompilableClassPlugin', array(new custom_compilable_class_plugin_obj(), 'call'), true);
$tpl = new Dwoo_Template_String('{CustomCompilableClassPlugin 4 5}');
$tpl->forceCompilation();
$this->assertEquals('20', $dwoo->get($tpl, array(), $this->compiler));
}
public function testCustomCompilableClassPluginInstanceAsModifier()
{
$dwoo = new Dwoo();
$dwoo->addPlugin('CustomCompilableClassPlugin', array(new custom_compilable_class_plugin_obj(), 'call'), true);
$tpl = new Dwoo_Template_String('{$foo=4}{$foo|CustomCompilableClassPlugin:5}');
$tpl->forceCompilation();
$this->assertEquals('20', $dwoo->get($tpl, array(), $this->compiler));
}
public function testCustomClassPluginInstance()
{
$dwoo = new Dwoo();
$dwoo->addPlugin('CustomClassPlugin', array(new custom_class_plugin_obj(), 'call'));
$tpl = new Dwoo_Template_String('{CustomClassPlugin 4 5}');
$tpl->forceCompilation();
$this->assertEquals('20', $dwoo->get($tpl, array(), $this->compiler));
}
public function testCustomClassPluginInstanceAsModifier()
{
$dwoo = new Dwoo();
$dwoo->addPlugin('CustomClassPlugin', array(new custom_class_plugin_obj(), 'call'));
$tpl = new Dwoo_Template_String('{$foo=4}{$foo|CustomClassPlugin:5}');
$tpl->forceCompilation();
$this->assertEquals('20', $dwoo->get($tpl, array(), $this->compiler));
}
}
function Dwoo_Plugin_CompilableFunctionPlugin_compile(Dwoo_Compiler $compiler, $number, $number2)
{
return "$number * $number2";
}
function Dwoo_Plugin_FunctionPlugin(Dwoo $dwoo, $number, $number2)
{
return $number * $number2;
}
class Dwoo_Plugin_CompilableClassPlugin extends Dwoo_Plugin implements Dwoo_ICompilable
{
public static function compile(Dwoo_Compiler $compiler, $number, $number2)
{
return "$number * $number2";
}
}
class Dwoo_Plugin_ClassPlugin extends Dwoo_Plugin
{
public function process($number, $number2)
{
return $number * $number2;
}
}
function custom_compilable_plugin(Dwoo_Compiler $cmp, $number, $number2)
{
return "$number * $number2";
}
function custom_plugin(Dwoo $dwoo, $number, $number2)
{
return $number * $number2;
}
class custom_compilable_class_plugin
{
public static function call($number, $number2)
{
return "$number * $number2";
}
}
class custom_class_plugin
{
public static function call($number, $number2)
{
return $number * $number2;
}
}
class custom_compilable_class_plugin_obj
{
public function call($number, $number2)
{
return "$number * $number2";
}
}
class custom_class_plugin_obj
{
public function call($number, $number2)
{
return $number * $number2;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment