2009-12-08 4 views
3

Я читал о том, как определить кодировку файла в PHP, и на каком-то блоге или где-то, что было предложено сделать это:Определить две функции или разветвить внутри одного?

if (function_exists('mb_detect_encoding')) { 
    function is_utf8($str) { 
     // do stuff using the mb* libraries 
    } 
} else { 
    function is_utf8($str) { 
     // do stuff manually 
    } 
} 

Для меня это выглядит очень неаккуратно, и может быть заменен это:

function is_utf8($str) { 
    if (...) { 
     // mb stuff here 
    } else { 
     // manual stuff here 
    } 
} 

Однако, я также вижу, что он также имеет некоторые преимущества. В зависимости от того, насколько сложным является оператор if, и как часто вызывается функция, это может быть намного более эффективным. Мой вопрос таков: в какой момент вы могли бы рассмотреть разделение функции на две, как в первом примере? Есть ли какие-либо другие плюсы/минусы, которые я пропустил?

Редактировать: Пожалуйста, не зацикливайтесь на примере здесь, вопрос об этой практике в целом.

ответ

5

Моя реакция кишки должна состоять из одного объявления функции is_utf8. Механизм PHP очень хорош в оптимизации, и накладные расходы на несколько вызовов до function_exists() должны быть незначительными.

+0

См. Мои контрольные показатели ниже. Вызов функции_exists() довольно ничтожен, но что-то об этом или структуре управления делает функцию вызова функции function_exists() занимает заметную сумму больше времени. –

+0

Внутренне PHP, вероятно, выполняет поиск типа 'function_exists()' для проверки перед вызовом функции * any *. При втором методе PHP должен выполнить два поиска - один для 'blarg()' и другой для 'sin()', который может учитывать дополнительное время. – leepowers

0

Я заранее извиняюсь за то, что, скорее всего, довольно уродливые PHP, но я хотел бы сделать что-то подобное:

if (function_exists('mb_detect_encoding')) { 
    function is_utf8_mb($str) { 
     // do stuff using the mb* libraries 
    } 
} 
function is_utf8_manual($str) { 
    // do stuff manually 
} 

if (function_exists('is_utf8_mb')) { 
    function is_utf8($str) { 
     is_utf8_mb($str) 
    } 
} else { 
    function is_utf8($str) { 
     is_utf8_manual($str) 
    } 
} 

То есть: is_utf8 вариант будет существовать в среде выполнения зависящей только если он может работать в этой среде. Каждый вариант находится в блоке кода минимального размера, необходимого для определения необходимости загрузки этого варианта и выполнения его функции. Основная причина заключается в том, что я думаю, что чем меньше объем пространства, который вам нужно написать для вашей функции, тем легче для читателя построить понимание поведения функции. Ваши глаза вынуждены путешествовать меньше, вам приходится меньше прокручивать, в общем, меньше всего этих тривиальных разочарований, связанных с пониманием функции в первый раз. Вторая причина заключается в том, что он обеспечивает лучший способ тестирования вашего кода - вы можете более легко автоматизировать проверку того, что альтернативные подпрограммы is_utf8 дают тот же результат, когда вы можете получить доступ ко всем из них в одно и то же время.

2

Стилистически, я склонен настаивать на втором. Если производительность является проблемой, вам следует рассмотреть возможность использования первого.

 
    if (function_exists("sin")) { 
     function baz($farfs) { 
      print "I am the first baz"; 
     } 
    } else { 
     function baz($farfs) { 
      print "I am the second baz"; 
     } 
    } 

    function blarg($fgar) { 
     if (function_exists("sin")) { 
      print "I am the first blarg"; 
     } else { 
      print "I am the second blarg"; 
     } 
    } 

    for ($i=0;$i

Я побежал это на моем рабочем месте здесь, и обнаружил, что совокупное время звонков База взяло где-то от 50-75% от совокупных вызовов blarg, в зависимости от того, будет ли функция испытания на самом деле существует.

Вот реальные цифры:

  • function_exists ("Foobar")
    • blarg: 36,64 мс
    • БАЗ: 14,71 мс
  • function_exists ("грех")
    • blarg: 35.24 мс
    • baz: 23.59 мс

Единственное различие между этими двумя функциями является условным и два дополнительных символов в выходных данных. Интересно, что 10001 звонков в функции__исследований принимают только 0,18 и 0,11 мс соответственно в двух тестах. Мне интересно, есть ли некоторые служебные данные вызова функции, которые не учитываются ни в одном из профилей.

Что касается стиля, тем не менее, мне действительно не нравится первый. Определение функции по имени в двух разных местах кажется теневым, что нужно делать, особенно если полагаться на нечетность в PHP, которая делает определения функций, которые не выполняются в глобальной области, в любом случае влияют на глобальную область. С другой стороны, мои предвзятости могут быть показаны, а остальная часть сообщества PHP может не иметь проблемы с использованием интерпретатора PHP как своего рода препроцессора в этом случае.

shrug Таковы вопросы стиля.

3

Хорошая практика, может быть, не в этом случае, но в целом может потребоваться использование ООП (объектов) с заводскими методами.

class my_utf8 
{ 
    // A static method that determine what object to create 
    public static function factory() { 
    if (function_exists('mb_detect_encoding')) { 
     return new my_utf8_with_mb; 
    } else { 
     return new my_utf8_without_mb; 
    } 
    } 
} 

class my_utf8_with_mb extends my_utf8 { 
    public function is_utf8($str) { 
     // do stuff using the mb* libraries 
    } 
} 

class my_utf8_without_mb extends my_utf8 { 
    public function is_utf8($str) { 
     // do stuff without the mb* libraries 
    } 
} 

И в вашем приложении:

global $myUtfInstance; 
// Call once 
$myUtfInstance = my_utf8::factory(); 

// later and forever... 
$myUtfInstance->is_utf8($str); 

Вы могли бы также включать одноплодной шаблон в зависимости от того, что вы делаете. Он не пропускает IF, но устраняет необходимость глобальной переменной.

class my_utf8 
{ 
    private static $instance; 

    public static function factory() { 
    if (function_exists('mb_detect_encoding')) { 
     return new my_utf8_with_mb; 
    } else { 
     return new my_utf8_without_mb; 
    } 
    } 


    public static function getInstance() 
    { 
    if (!self::$instance) { 
     self::$instance = self::factory(); 
    } 

    return self::$instance; 
    } 
} 

И в вашем коде:

my_utf8::getInstance()->is_utf8($str); 
1

По умолчанию, всегда идет с наиболее читаемым раствором. Если этот фрагмент кода окажется значительным (измеренным, а не предполагаемым), то вы его оптимизируете.

0

Здесь есть два аспекта: производительность (не платите за то, что вам не нужно) и читаемость.

Как многие мудрые плакаты говорят: не беспокойтесь о производительности, пока это не станет проблемой.

Но относительно читаемости, на мой взгляд, функция должна показывать как можно меньше уровней ответственности. Функции, которые делают только одно, легче всего понять.

Ваш вопрос на самом деле о том, «как я должен смешивать две обязанности»:

  1. , что: обнаружить наличие библиотеки, и «отправка» для правильного кодового блока
  2. как использовать библиотеку против того, как обойтись.

Вот почему я действительно создал два «слоя»: один уровень, отправляющий соответствующую функцию, и еще один слой, содержащий «блоки кода», завернутые в функцию с собственным именем.

И у вас все еще есть выбор, следует ли явно выполнять диспетчеризацию, или использовать возможность PHP объявлять функции «на лету».

// functionality: defines how to detect utf8 encoding 
// 

function is_utf8_mb($arg) { 
... // using the mb library 
} 

function is_utf8_bare($arg) { 
... // hand coded 
} 

// dispatching layer: decide what library to use 
// 

// option 1: define on-the-fly 
function define_utf8_function() { 
    if(function_exists('mb_detect_encoding')) { 
    function is_utf8($arg) { return is_utf8_mb($arg); } 
    } else { 
    function is_utf8($arg) { return is_utf8_bare($arg); } 
    } 
} 

// option 2: check the dispatching on each function call 
function is_utf8_runtimedispatch($arg) { 
    if(function_exists('mb_detect_encoding')) 
    return is_utf8_mb($arg); 
    else 
    return is_utf8_bar($arg); 
} 
Смежные вопросы