Статьи

Практический рефакторинг PHP: метод переименования

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

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

Зачем переименовывать?

Маленькие методы хороши, верно? Мы можем извлекать и извлекать код, пока они не станут длиннее нескольких строк.

Проблема, однако, в том, что если мы не будем тщательно называть извлеченные методы , нам будет трудно следовать цепочке вызовов. Простое извлечение кода бесполезно, если результатом является цепочка общих вызовов, таких как process () -> forward () -> compute () -> makeSomething ().

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

Трудно сразу получить правильное название для метода. Некоторые решения этой проблемы — сначала написать вызов (в тестовом или другом коде), а не сам метод; или чтобы избежать общих глаголов, таких как process (). Тем не менее, простая стратегия состоит в том, чтобы начать с достаточно хорошего имени и переименовать его перед публикацией вашего Api. Пока у вас есть контроль над всем вашим кодом и частая интеграция, переименование — это не дорогая операция.

меры

  1. Проверьте суперклассы и подклассы : если метод присутствует более чем в одной точке иерархии, его следует изменить везде.
  2. Объявите новый метод с новым именем, дублируя исходный.
  3. Сделайте так, чтобы старый метод вызывал новый, чтобы удалить дублирование.

Теперь вы можете изменить вызовы со старого на новое имя по одному за раз . Это пример параллельных конструкций, описанных Кентом Беком в разделе «Адаптивный дизайн».

Когда вы закончите, удалите старый метод или временно вставьте исключение в его начало, чтобы увидеть, вызывается ли оно еще где-нибудь. Здесь может помочь только хороший набор тестов — динамичность PHP означает, что нет никаких проверок во время компиляции на существование вызываемого метода.

Если вы не используете магические функции, такие как __call () или вызовы, такие как $ object -> $ method (), grep также может быть полезен:

grep -r 'methodName(' folder/

Используйте grep -rl, если список перегружен, чтобы просто показать список файлов вместо всех вхождений.

пример

В исходном состоянии UserRepository содержит неясный метод snafucatedUsers (). Мы просто вернем константу для имитации сложных вычислений, так как мне интересно показать пример шагов для этого рефакторинга и ничего более, что могло бы вас отрицать.

<?php
class RenameMethod extends PHPUnit_Framework_TestCase
{
    public function testSimulatesClientCode()
    {
        $repository = new UserRepository();
        $this->assertEquals(0, $repository->snafucatedUsers());
    }
}

class UserRepository
{
    public function snafucatedUsers()
    {
        // ...complex calculations...
        return 0;
    }
}

Мы создаем новый метод. Нет суперклассов или подклассов для проверки. Мы просто копируем другой метод и вставляем его, исправляя имя.

class UserRepository
{
    public function snafucatedUsers()
    {
        // ...complex calculations...
        return 0;
    }

    public function numberOfUsersWithoutAPublicProfile()
    {
        // ...complex calculations...
        return 0;
    }
}

Мы заставляем старый метод делегировать новый.

class UserRepository
{
    public function snafucatedUsers()
    {
        return $this->numberOfUsersWithoutAPublicProfile();
    }

    public function numberOfUsersWithoutAPublicProfile()
    {
        // ...complex calculations...
        return 0;
    }
}

Мы можем изменить различные звонки сейчас. Тест имитирует весь клиентский код, который нам нужно проверить. Мы можем сделать это один вызов за раз, запуская тесты после каждого шага.

<?php
class RenameMethod extends PHPUnit_Framework_TestCase
{
    public function testSimulatesClientCode()
    {
        $repository = new UserRepository();
        $this->assertEquals(0, $repository->numberOfUsersWithoutAPublicProfile());
    }
}

class UserRepository
{
    public function snafucatedUsers()
    {
        return $this->numberOfUsersWithoutAPublicProfile();
    }

    public function numberOfUsersWithoutAPublicProfile()
    {
        // ...complex calculations...
        return 0;
    }
}

Теперь мы можем удалить старую версию метода, поскольку grep не находит больше вызовов:

[14:51:29][giorgio@Galen]$ grep -r 'snafucated' .
[14:52:11][giorgio@Galen]$ 

 

Окончательный результат:

class UserRepository
{
    public function numberOfUsersWithoutAPublicProfile()
    {
        // ...complex calculations...
        return 0;
    }
}