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

в 20:00, , рубрики: Без рубрики

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

Автор: Lubaev

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js