Для получения полного доступа
зарегистрируйтесь

samdark    331   28 230


Engineer, active OpenSource member, one of Yii core team members and its representative in PHP-FIG.

Wrote a book. Works at Stay.com building cool stuff using Yii and other tools.

  • Voronezh
  • Yii, Stay.com
  • Yii, PHP, JavaScript, Java, Android, SQL, OOP, OOD
  • VSU, Computer Science, master
  • Зарегистрирован год назад

Для начала задаём сам шаблон прямо в HTML страницы:

<script type="html/tpl" id="my-template">
<div class="item">
    <h1>{title}</h1>
    <p class="description">{description}</p>
</div>
</script>

Далее реализовываем сам метод получения строки с заменёнными плейсхолдерами:

function renderTemplate(name, data) {
    var template = document.getElementById(name).innerHTML;

    for (var property in data) {
        if (data.hasOwnProperty(property)) {
            var search = new RegExp('{' + property + '}', 'g');
            template = template.replace(search, data[property]);
        }
    }
    return template;
}

Использовать можно так:

var html = renderTemplate('my-template', {
    title: "My cool thing",
    description: "It is really cool, isn't it?"
});

Стоит отметить, что экранирование спецсимволов не делается, так что будьте осторожны.

<?php
$facebookParams = array(
    'app_id' => 12345,
    'u' => 'http://yiiframework.ru/',
);
?>

<a href="https://www.facebook.com/sharer/sharer.php?<?php echo http_build_query($facebookParams) ?>" target="_blank" rel="noopener noreferrer">Facebook</a>
<?php
$twitterParams = [
    'hashtags' => 'yii',
    'original_referer' => 'http://yiiframework.ru/',
    'text' => 'Я участвую в yiiframework.ru: ',
    'url' => 'http://yiiframework.ru/',
];
?>

<a href="https://twitter.com/intent/tweet?<?php echo http_build_query($twitterParams) ?>" target="_blank" rel="noopener noreferrer">Tweet</a>

Иногда случается сдедать описку в названии тега и пушнуть его. Не беда, всё поправимо:

git tag new old
git tag -d old
git push origin :refs/tags/old
git push --tags

Если у вас в приложении всего один язык, не обязательно использовать Yii::t() для множественных форм:

echo Yii::$app->i18n->format('На диване {n, plural, =0{нет кошек} =1{лежит одна кошка} one{лежит # кошка} few{лежит # кошки} many{лежит # кошек} other{лежит # кошки}}!', ['n' => 0], 'ru_RU');

Для удобства это можно завернуть в функцию:

function f($message, $params)
{
    return Yii::$app->i18n->format($message, $params, 'ru_RU');
}

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

function supportsAnsiColors()
{
  return DIRECTORY_SEPARATOR === '\\'
  ? getenv('ANSICON') !== false || getenv('ConEmuANSI') === 'ON'
  : function_exists('posix_isatty') && @posix_isatty(\STDOUT);
}
  • DIRECTORY_SEPARATOR === '\\' — проверка на Windows.
  • getenv('ANSICON') !== false — проверка запуска через ANSICON.
  • getenv('ConEmuANSI') === 'ON' — проверка запуска через ConEmu.
  • function_exists('posix_isatty') && @posix_isatty(\STDOUT) — проверка на интерактивный терминал UNIX.

Нормально работающий с юникодом аналог 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);
}

Такой подход к записи используется в моей библиотеке Sitemap для генерации огромных карт сайтов, содержащих сотни тысяч URL.

// пишем данные в буфер чтобы не дёргать диск слишком часто
$bufferSize = 1000;

$filePath = 'test.xml';

$writer = new XMLWriter();
// для буфера используем память
$writer->openMemory();


$writer->startDocument('1.0', 'UTF-8');
$writer->setIndent(true);
$writer->startElement('test');

while ($i < 10000) {                  
	if ($i % $bufferSize) {
		// если буфер полон, скидываем его в файл
		file_put_contents($filePath, $writer->flush(true), FILE_APPEND);
	}
	$writer->writeElement('item', $i);
}

$this->writer->endElement();

$this->writer->endDocument();

// пишет остаток буфера в файл
file_put_contents($filePath, $writer->flush(true), FILE_APPEND);

Чтобы удалить кеш фрагмента в Yii 2.0 необходимо специальным образом сформировать ключ.

function deleteFragmentCacheByKey($key)
{
    return Yii::$app->cache->delete(['yii\widgets\FragmentCache', $key]);
}

Проверить, что в двух массивах одни и те же элементы, не учитывая сортировку, требудется довольно часто. А вот как это сделать в PHPUnit не совсем очевидно.

$array = ['b', 'a'];
$this->assertEquals(['a', 'b'], $array, '', 0.0, 10, true);

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

Решение, на самом деле, простое. Разбиваем строку по разным видам пробелов (\s тут весьма кстати) и не забываем /u для того, чтобы метасимволы нормально работали с юникодом.

public static function countWords($string)
{
    return count(preg_split('/\s+/u', $string, null, PREG_SPLIT_NO_EMPTY));
}
git reset --soft HEAD~3
git commit -m 'new commit message'

3 заменить на N.

Работает и на уже push-нутых ветках, если потом делать git push --force. Последняя команда заменят ветку целиком, так что с ней надо быть особо осторожным.

Перемешивать значения массива раз в неделю можно ничего не сохраняя где либо. Решние найдено на StackOverflow.

Оно основано на инициализации генератора случайных чисел, который используется shuffle(), значением, меняющимся раз в неделю. Функция date('W') даёт нам номер недели в году, что идеально подходит для нашей задачи. После перемешивания массива генератор случайных чисел приводится в нормальное состояние вызовом srand() без аргументов.

srand(date('W'));
shuffle($array);
srand();

Решение оказалось не вполне рабочим :(

Улучшенное решение задачи из http://gostash.it/ru/stashes/1452:

  • Разбивает строку по ближайшему к центру пробелу вне зависимости от того, справа или слева он от центра.
  • Работает с UTF-8.
  • Отдаёт массив, который можно применить не только в HTML.

Для проверки:

var_dump(splitInHalf('this is a hyperlooping'));
var_dump(splitInHalf('this hyperlooping'));
function splitInHalf($string)
{
    $middle = mb_strrpos(mb_substr($string, 0, floor(strlen($string) / 2), 'UTF-8'), ' ', null, 'UTF-8') + 1;

    return [
        mb_substr($string, 0, $middle - 1, 'UTF-8'),
        mb_substr($string, $middle, null, 'UTF-8')
    ];
}

Иногда требуется, чтобы определённые ключи в массиве оказались в начале в определённом порядке.

$data = [
    'orange' => 'orange',
    'apple' => 'tasty',
    'carpet' => 'old',
    'car' => 'fast',
];

$result = orderByKeys($data, ['car', 'carpet']);

Получим:

$data = [
    'car' => 'fast',
    'carpet' => 'old',
    'orange' => 'orange',
    'apple' => 'tasty',    
];
function orderByKeys(array $array, array $keys)
{
    foreach ($keys as $k => $v) {
        if (!array_key_exists($v, $array)) {
            unset($keys[$k]);
        }
    }

   return array_replace(array_flip($keys), $array);
}

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

Пример:

echo getCurrencySymbol('EUR');
echo getCurrencySymbol('GBP');

выведет и £.

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

echo getCurrencySymbol('RUR', 'ru_RU');

выведет р..

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

function getCurrencySymbol($currencyCode, $locale = 'en_US')
{
    $formatter = new \NumberFormatter($locale . '@currency=' . $currencyCode, \NumberFormatter::CURRENCY);
    return $formatter->getSymbol(\NumberFormatter::CURRENCY_SYMBOL);
}

Так твиттер борется со вставкой себя в <iframe>.

if (window.top !== window.self) {
    document.write = "";
    window.top.location = window.self.location;
    setTimeout(function () {
        document.body.innerHTML = '';
    }, 1);
    window.self.onload = function (evt) {
        document.body.innerHTML = '';
    };
}

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

$last = array_pop($array);
foreach ($array as $value) {
   // делаем что-либо с каждым элементом
}
// делаем что-либо с последним элементом $last

Запрос позволяет эффективно выбрать 10 последних комментариев, максимум по одному на пост.

SELECT *
FROM comment c1
LEFT JOIN comment c2 ON c1.id < c2.id AND c1.post_id = c2.post_id
WHERE c2.id IS NULL
ORDER BY c1.id DESC
LIMIT 10