Сниппеты:
Подраздел:
Языки:

IStranger
  • Репутация: 4
  • Сниппеты: 8
  • Ревизии: 0

Высокопроизводительная функция проверяет массив на предмет содержания целочисленных значений (либо целочисленных строк):


/**
 * Checks whether all elements of an array are integers (integer value or string with integer value).
 * Note: this is very efficient method can be used for array with 10000+ items.
 *
 * @param int[]|string[] $array One dimensional array to check
 *
 * @return bool
 */ 
function hasOnlyIntEntries(array $array)
{
    return ctype_digit(join('', $array));
}
IStranger
  • Репутация: 4
  • Сниппеты: 8
  • Ревизии: 0

Часто бывает необходимо удалить классы, начинающиеся с определенной строки. Например: has-state-active, has-state-pending, has-state-disabled. Простейший и очевидный способ - это использовать символы подставноки: has-state-*.

Следующая функция поддерживает их (требуется jQuery):

/**
 * Removes CSS classes of element using wildcards:
 *
 * @example
 * <code><pre>
 *
 *          // create some element
 *      var $element = $('<div id="#some-element"/>')
 *                          .addClass('base-class has-state-active item item-75')
 *                          .appendTo('body');
 *
 *          // remove classes with few prefixes
 *      removeClassWildcard( $element, 'has-state-* item-*');
 *
 *          // display element classes
 *      console.log($element.attr('class'));    // >> "base-class item"
 *
 * </pre></code>
 *
 * @param {jQuery|*}    $element
 * @param {String}      removals        Classes to delete, for example: 'foo-* bar-*'
 * @returns {jQuery|*}                  Passed element
 */
function removeClassWildcard($element, removals) {
    if (removals.indexOf('*') === -1) {
        // Use native jQuery methods if there is no wildcard matching
        $element.removeClass(removals);
        return $element;
    }

    var patt = new RegExp('\\s' +
            removals.replace(/\*/g, '[A-Za-z0-9-_]+').split(' ').join('\\s|\\s') +
            '\\s', 'g');

    $element.each(function (i, it) {
        var cn = ' ' + it.className + ' ';
        while (patt.test(cn)) {
            cn = cn.replace(patt, ' ');
        }
        it.className = $.trim(cn);
    });

    return $element;
}

Пример:

Следующий пример демонстрирует использование данной функции:


  // create some element
var $element = $('<div id="#some-element"/>')
                  .addClass('base-class has-state-active item item-75')
                  .appendTo('body');

  // remove classes with few prefixes
removeClassWildcard( $element, 'has-state-* item-*');

  // display element classes
console.log($element.attr('class'));    // >> "base-class item"
IStranger
  • Репутация: 4
  • Сниппеты: 8
  • Ревизии: 0

"Золотые" правила оптимизации фронтэнда часто рекомендуют подключать все JS скрипты в конце страницы. Однако обычно нам строго необходимо подлючать <script src="//jquery.js"> в <head> страницы, и мы не можем его оттуда удалить, поскольку контент страницы может содержать onReady-обработчики, например $(function(){ ... }). Такие обработчики обычно вставляются автоматически сторонними виджетами, CMS, фреймворками.

Этот короткий скрипт позволяет переместить подключение jquery.js из <head> в конец <body> без изменения имеющихся onReady-обработчиков на странице.

Код:

<head>
	<script>
		// Fallback code for the jQuery inline scripts on pages:
      if (window.jQuery === undefined) {
          window.jQueryReadyHandlers = [];

          window.$ = window.jQuery = function (callback) {
              window.jQueryReadyHandlers.push(callback);
              return window.$;
          };

          window.$.ready = window.$;
      }
  	</script>
    <!-- ...some head items -->
</head>
<body>

	<!-- ...some page content -->
    
    <script> 
    	// some onReady-handlers
      $(function(){
          console.log('First callback');
      });

      jQuery(document).ready(function(){
          console.log('Second callback');
      });
    </script>
    
    <!-- ...some page content -->


	<script src="//js/jquery.min.js"></script>
    <script>
    	jQuery(window).load(function(){
        	if(window.jQueryReadyHandlers) { 
            	$.each(window.jQueryReadyHandlers, function(index,func){  
                	$(func);
                });
            }
        });
    </script>
</body>
IStranger
  • Репутация: 4
  • Сниппеты: 8
  • Ревизии: 0

Когда мы работаем с каким либо API интерфейсом, очень часто они имеют ограничения на количество выполняемых запросов в единицу времени. Данный хелпер призван помочь решить данную проблемы наиболее эффективным способом.

Код хелпера:


/**
 * Helper for work with some API.
 */
class ApiHelper
{

    /**
     * Wraps specified callback function and retries of execution in the case when callback throws specified exception.
     * Used Exponential BackOff algorithm for evaluating of timeouts between retries of callback execution.
     *
     * Example:
     * <code>
     *  $sendHttpRequest = function ($pageNum) use ($httpClient){
     *      $httpClient->sendGet('http://example.com?pageNum=' . $pageNum);
     *  };
     *
     *  $wrappedFn = ApiHelper::wrapUsingExponentialBackOff($sendHttpRequest, 5000, '\TooManyRequestsHttpException');
     *
     *  // We perform 100 requests. But remote server has RateLimit.
     *  for ($i = 1; $i <= 100; $i++) {
     *      // $sendHttpRequest($i);     // request without wrapper
     *      $wrappedFn($i);              // request with wrapper
     *      // this wrapper retry callback execution in the case of \TooManyRequestsHttpException exception.
     *  }
     * </code>
     *
     * @param \Closure $callbackFn                  Callback function.
     * @param int      $maxSleepMs                  Max value of timeout between callback execution.
     * @param string   $rateLimitExceptionClassName Exception that should throw callback on rate limit.
     * @param int      $maxRetries                  Max number of retries.
     * @param \Closure $onTooManyRequest            Callback function that performed on each RateLimit exception.
     *
     * @return \Closure
     */
    public static function wrapUsingExponentialBackOff(\Closure $callbackFn, $maxSleepMs, $rateLimitExceptionClassName, $maxRetries = 10, \Closure $onTooManyRequest = null)
    {
        $wrapFn = function () use ($callbackFn, $maxSleepMs, $rateLimitExceptionClassName, $maxRetries, $onTooManyRequest) {

            $currentTry    = 0;
            $retriesRemain = $maxRetries;

            while ($retriesRemain-- > 0) {

                try {
                    $currentTry++;
                    return call_user_func_array($callbackFn, func_get_args());

                } catch (\Exception $exception) {

                    // retries only throttling errors
                    if ($exception instanceof $rateLimitExceptionClassName) {
                        $backOffDuration = static::_getSleepDuration($currentTry, 10, $maxSleepMs);

                        if ($onTooManyRequest) {
                            $onTooManyRequest($exception, $backOffDuration, $retriesRemain, $currentTry);
                        }

                        usleep($backOffDuration * 1000);
                    } else {
                        throw $exception;
                    }

                }

            }

            throw new \Exception('ExponentialBackOff: Too many retries of function call [maxRetries=' . $maxRetries . ']');
        };

        return $wrapFn;
    }

    protected static function _getSleepDuration($currentTry, $minSleepMs, $maxSleepMs)
    {
        $currentSleepMs = (int)($minSleepMs * pow(2, $currentTry));

        return min($currentSleepMs, $maxSleepMs);
    }
}

Как это использовать

  1. Подготовь функцию (\Closure), которая выполняет некоторый API метод. Эта функция должна бросать исключение (определенного класса) каждый раз, когда натыкается на ограничение по скорости выполнения.
  2. "Оберни" эту функцию с помощью метода ApiHelper::wrapUsingExponentialBackOff(). Этот метод вернет функцию, которая вызывается с теми же самыми аргументами, что и оригинальная.
  3. Выполняй в коде "обернутую" версию функции вместо оригинальной.
$sendHttpRequest = function ($pageNum) use ($httpClient) {
    $httpClient->sendGet('http://example.com?pageNum=' . $pageNum);
};

$wrappedFn = ApiHelper::wrapUsingExponentialBackOff($sendHttpRequest, 5000, '\TooManyRequestsHttpException');

// We perform 100 requests. But remote server has RateLimit.
for ($i = 1; $i <= 100; $i++) {
    // $sendHttpRequest($i);     // request without wrapper
    $wrappedFn($i);              // request with wrapper
    // this wrapper retry callback execution in the case of \TooManyRequestsHttpException exception.
}

Как это работает

Этот хелпер использует "Exponential backoff" алгоритм.

Основная идея этого алгоритма в том, чтобы вставлять временные задержки при выполнении операций. Каждый раз, натыкаясь на "ограничение", автоматически вставляется задержка перед попыткой повторного выполнения. Если вновь натыкаемся на "ограничение", задержка увеличивается (экспоненциально от номера попытки). "Обернутая" функция $wrappedFn будет пытаться повторно выполнять оригинальный код $sendHttpRequest, если тот выбросит определенное исключение. Число попыток, разумеется, ограничено (настраивается в ApiHelper::wrapUsingExponentialBackOff()).

Таким образом, данный подход позволяет выполнять запросы к API интерфейсу со скоростью, максимально приближенной к разрешенной этим самым API.

Kosuha606
  • Репутация: 7
  • Сниппеты: 5
  • Ревизии: 0

Этот класс можно использовать в случаях, когда необходимо заставить барузеры клиентов обновить ресурсы ( css, js ) при их изменении в git. Требует доступного на выполнение git.

Этот пример оптимизирован по совету пользователя matweew. Улучшенную версию смотрите ниже после этой.

Первая версия:

<?php

class HashedAsset
{
    public $hash;
    
    public function init()
    {
        exec('git describe --always',$version_hash);
        if (isset($version_hash[0])) {
            $this->hash = md5($version_hash[0]);    
        }
    }
}

Продолжение

Kosuha606
  • Репутация: 7
  • Сниппеты: 5
  • Ревизии: 0

Небольшая функция для определения нужно ли подсветить какой-нибудь пункт меню как активный в зависимости от текущего url. Применимо к ЧПУ ссылкам, для запросов с параметрами придется доработать.

Продолжение

Kosuha606
  • Репутация: 7
  • Сниппеты: 5
  • Ревизии: 0

У меня на работе появилась задачка сделать небольшой проект, для простого просмотра картинок из папок локальной сети.. И как то так само собой сложилось, что я написал вот такой класс для рендеринга видов ( просто я люблю Yii2 да и вообще MVC ). Вот решил поделиться и спросить у занющих людей насколько рабочим в реальных проектах был бы этот класс??? Возможно ли решить задачу по другому?? Просто это первое что пришло в голову и есть сомнения в качестве...

Реализацию yii2 рендеринга не смотрел, так как само как то получилось... но посмотрю как нибудь обязательно...

Еще дополню, в проекте не использовался вообще никакой фреймворк... просто приложение на PHP.

Продолжение

Gravatar image
maxyc
  • Репутация: 25
  • Сниппеты: 4
  • Ревизии: 0
 $arr = [1,2,3]
srand(date('W'));
shuffle($array);
srand();

И никаких тебе сохранений промежуточных состояний

Gravatar image
Иван Орлов
  • Репутация: 4
  • Сниппеты: 1
  • Ревизии: 0
# m h dom mon dow   command
/usr/bin/php -q /var/www/site/yii sitemap >/dev/null 2>&1

dow: sun mon tue wed thu fri sat
mon: jan feb mar apr may jun jul aug sep oct nov dec 

@reboot 	Запуск при загрузке 	
@yearly 	Раз в год 	0 0 1 1 *
@annually 	Тоже что и @yearly 	
@monthly 	Раз в месяц 	0 0 1 * *
@weekly 	Раз в неделю 	0 0 * * 0
@daily 	 	Раз в день 	0 0 * * *
@midnight 	В полночь (00:00) 	
@hourly 	Каждый час 	0 * * * *
samdark
  • Репутация: 265
  • Сниппеты: 49
  • Ревизии: 4

Нормально работающий с юникодом аналог ucfirst().

function mb_ucfirst($string, $encoding = 'UTF-8') {
  $firstChar = mb_strtoupper(mb_substr($string, 0, 1, $encoding), $encoding);
  return $firstChar . mb_substr($string, 1, mb_strlen($string, $encoding), $encoding);
}