PHP_Over: имитатор перегрузок

image Перегрузка функций — это механизм, который позволяет двум родственным функциям иметь одинаковые имена.

Допустим необходимо реализовать функции, которые будут вычислить объем следующих фигур: куб шар цилиндр конус пирамида прямоугольный параллелепипед // Объем куба function Volume_Cube (/*int*/ $side) { return pow ($side, 3); }

// Объем шара function Volume_Sphere (/*double*/ $radius) { return ((4/3) * M_PI * pow ($radius, 3)); }

// Объем цилиндра function Volume_Cylinder (/*double*/ $radius, /*int*/ $height) { return (M_PI * pow ($radius, 2) * $height); }

// Объем конуса function Volume_Сone (/*int*/ $height, /*double*/ $radius) { return ((⅓) * M_PI * pow ($radius, 2) * $height); }

// Объем пирамиды function Volume_Pyramid (/*int*/ $square, /*int*/ $height) { return ((⅓) * $square * $height); }

// Объем прямоугольного параллелепипеда function Volume_Cuboid (/*int*/ $length, /*int*/ $width, /*int*/ $height) { return ($length * $width * $height); } Это делает ситуацию сложнее, чем она есть на самом деле. Другими словами, при одних и тех же действиях (вычисление объема) программисту необходимо помнить имена всех шести функций вместо одного.

PHP_Over регистрирует значение, которое может быть вызвано как функция, по заданному количеству и/или значению типа аргумента, которое должно быть перегружено в процессе вызова.

require 'src/php_over/PHP_Over.php';

$Volume = new PHP_Over; $Volume →overload ('%i', function ($side) { return pow ($side, 3); }) →overload ('%d', function ($radius) { return ((4 / 3) * M_PI * pow ($radius, 3)); }) →overload ('%d', '%i', function ($radius, $height) { return (M_PI * pow ($radius, 2) * $height); }) →overload ('%i', '%d', function ($height, $radius) { return ((1 / 3) * M_PI * pow ($radius, 2) * $height); }) →overload ('%i', '%i', function ($square, $height) { return ((1 / 3) * $square * $height); }) →overload ('%i', '%i', '%i', function ($length, $width, $height) { return ($length * $width * $height); });

$Volume (5); // 125 $Volume (5.); // 523.5987755983 $Volume (3., 10); // 282.74333882308 $Volume (10, 2.); // 41.887902047864 $Volume (15, 9); // 45 $Volume (15, 9, 3); // 405 Теперь достаточно знать только одно имя $Volume, а для вычисления объема требуемой фигуры необходимо указать то количество и те типы аргументов, которые требуются.

Допустим необходимо изменить набор фигур для которых требуется вычислить объем:

куб шар цилиндр конус пирамида прямоугольный параллелепипед правильный тетраэдр призма // … Part 1

$Volume →override ('%i', function ($edge) { return (pow ($edge, 3) * sqrt (2) / 12); }) →override ('%i', '%i', function ($square, $height) { return ($square * $height); });

$Volume→invokeTo (5); // 14.73139127472 $Volume→invokeTo (5.); // 523.5987755983 $Volume→invokeTo (3., 10); // 282.74333882308 $Volume→invokeTo (10, 2.); // 41.887902047864 $Volume→invokeTo (15, 9); // 135 $Volume→invokeTo (15, 9, 3); // 405

Допустим необходимо избавиться от некоторых перегружаемых функций, в процессе выполнения:

правильный тетраэдр шар цилиндр конус призма прямоугольный параллелепипед // … Part 1 // … Part 2

$Volume →override ('%i', '%d') →override ('%d', false);

function wrapperToVolume () { global $Volume;

try { return $Volume→invokeArgsTo (func_get_args ()); } catch (Exception $exp) { return $exp→getMessage (); } }

wrapperToVolume (5); // 14.73139127472 wrapperToVolume (5.); // Вызов неопределенной ранее функции wrapperToVolume (3., 10); // Вызов неопределенной ранее функции wrapperToVolume (10, 2.); // Вызов неопределенной ранее функции wrapperToVolume (15, 9); // 135 wrapperToVolume (15, 9, 3); // 405 Скорость выполнения псевдо-перегружаемой функции, само собой, оставляет за собой право желать лучшего: require 'src/php_over/PHP_Over.php';

define ('NUMBER_OF_OPERATIONS_TEST_PHP_OVER', 1000000);

$array1 = array ('a' => 'green', 'b' => 'brown', 'c' => 'blue', 'red'); $array2 = array ('a' => 'green', 'b' => 'yellow', 'blue', 'red');

function my_array_intersect_assoc ($array1, $array2) { return array_intersect_assoc ($array1, $array2); }

$php_over = new PHP_Over; $php_over→overload ('%a', '%a', 'my_array_intersect_assoc');

function Test_1() { global $array1, $array2;

$i = 0; $t = microtime (true); while ($i++ < NUMBER_OF_OPERATIONS_TEST_PHP_OVER) { array_intersect_assoc($array1, $array2); }

return (microtime (true) — $t); }

function Test_2() { global $array1, $array2;

$i = 0; $t = microtime (true); while ($i++ < NUMBER_OF_OPERATIONS_TEST_PHP_OVER) { my_array_intersect_assoc($array1, $array2); }

return (microtime (true) — $t); }

function Test_3() { global $php_over, $array1, $array2;

$i = 0; $t = microtime (true); while ($i++ < NUMBER_OF_OPERATIONS_TEST_PHP_OVER) { $php_over->invokeTo ($array1, $array2); }

return (microtime (true) — $t); }

//========================================================================== // | Count | PHP 5.3(average) | PHP 5.4(average) | PHP 5.5(average) | //========================================================================== // Test_1×5 | 6.56 sec | 5.86 ses | 5.69 sec | //========================================================================== // Test_2×5 | 11.11 sec | 10.02 sec | 9.51 sec | //========================================================================== // Test_3×5 | 148.6 sec | 123.6 sec | 115.4 sec | //========================================================================== .git: PHP_Over

© Habrahabr.ru