...

суббота, 19 апреля 2014 г.

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 ((1/3) * M_PI * pow($radius, 2) * $height);
}

// Объем пирамиды
function Volume_Pyramid(/*int*/ $square, /*int*/ $height)
{
return ((1/3) * $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

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий