¿Cuantas veces te ha pasado que hecho una pull request y aparecen 300 cambios porque el code style es distinto? ¿O qué nos ha faltado añadir un tipado en los parámetros de una función? ¿Cómo saber si tenemos alguna librería vulnerable? A mí estas cosas me han ocurrido más de una vez por eso intento tener todas estos temas automatizados, ya sea por medio de librerías, teniendo plantillas o atajos.

La idea que hay detrás de automatizar es tener un feedback loop lo más rápido posible y poder darnos cuenta de esos errores/mejoras cuanto antes. Quien me conoce sabe que más de una vez he contado la metáfora de la mochila: mientras estamos desarrollando llevamos una mochila con varios temas: la carga cognitiva intríniseca que hay en programar, ver ese trozo de código que habría que modificar, no perder el norte porque la idea es añadir X feature, los tests, el code style, si hay que añadir un caso nuevo a los tests, si los test son legibles, si el código lo entenderé dentro de 2 semanas, como afecta ese cambio al resto de la aplicación… tenemos que mantener la mochila lo más «vacía» posible para de verdad centrarnos en lo importante.

Photo by Tim Samuel on Pexels.com

Por todo eso, en este post vamos a contar una serie de librerías, plantillas,etch para automatizar todo lo posible un pryecto en PHP y hacer que podamos dedicarle más tiempo a pensar y menos a recordar cómo era ese comando que tienes que lanzar o si la llave iba en la misma linea o en la siguiente. Vamos a hablar solo de librerías y de nuestro entorno local, pero debemos de tener en cuenta que todo lo que vamos a contar podríamos llevarlo a nuestro pipeline de Integración Continua con tan solo rellenar un YML

Automatizando con librerías

Empecemos por que librerías son útiles para añadir al composer.json para tener a punto el estilo de código, el análisis estático, los test, los gazapos al escribir incorrectamente un fichero…

    "require-dev": {
        "ekino/phpstan-banned-code": "^0.3.1",
        "friendsofphp/php-cs-fixer": "^2.16",
        "infection/infection": ">= 0.16",
        "korbeil/phpstan-generic-rules": "^0.2.4",
        "php-parallel-lint/php-parallel-lint": "^1.2",
        "phpstan/phpstan": "^0.12.18",
        "phpstan/phpstan-deprecation-rules": "^0.12.2",
        "phpstan/phpstan-phpunit": "^0.12.7",
        "phpunit/phpunit": "^9"
    },

Todas estas librerías son comandos a ejecutar y como tenerlos todos en la cabeza puede ser un poco complicado una idea es añadirlos como scripts al composer.json

 "scripts": {
        "fixer": "php-cs-fixer fix",
        "lint": "parallel-lint --exclude vendor .",
        "phpstan": "phpstan analyse -c .phpstan.neon --debug --level 8 --memory-limit=1G src tests",
        "test": "phpunit",
        "test-mutation": "infection --threads=4 -s --only-covered --log-verbosity=all"
    }

Ahora vamos a ir desgranando cada una de las librerías que hemos añadidos

Errores de sintaxis

Aunque tengamos tests, lo mismo no cubren todo nuestro pipeline o hemos editado algún fichero que no está cubierto por ningún test. Quizás el IDE nos avise, pero no nos hemos dado cuenta de que se nos ha escapado un :
PHP tiene una función nativa para chequear la sintaxis

php -l index.php

El problema que ese chequeo es lento, así que podemos automatizarlo utilizando https://github.com/php-parallel-lint/PHP-Parallel-Lint y añadiendo al composer.json

composer require --dev php-parallel-lint/php-parallel-lint

Para ejecutarla por ejemplo cuando estamos en un proyecto de Symfony sería:

vendor/bin/parallel-lint --exclude app --exclude vendor .

Estilo de código

La herramienta aquí por excelencia es https://github.com/FriendsOfPHP/PHP-CS-Fixer para chequear el estilo. Tenemos distintos estándares o podemos crear el nuestro (mejor no). Aquí incluso podemos añadir la opción de «auto-commit fixer» para que se añadan commits con el formato correcto.

Para configurarlo y que todas las personas del equipo tengamos el mismo estilo de código, independientemente de si usamos PHPStorm o vim es tener un fichero llamado .php_cs.dist en la raíz de nuestro proyecto. De este modo todas las personas del equipo formatearán el código de la misma manera con tan solo ejecutar composer fixer

<?php

$finder = PhpCsFixer\Finder::create()
    ->in(__DIR__ . '/src')
    ->in(__DIR__ . '/tests');

return PhpCsFixer\Config::create()
    ->setUsingCache(true)
    ->setRiskyAllowed(true)
    ->setRules([
        // PSR-2 rules
        '@PSR2' => true,
        '@Symfony' => true,

        // Custom rules
        'blank_line_after_opening_tag' => true,
        'braces' => ['allow_single_line_closure' => true],
        'cast_spaces' => true,
        'concat_space' => ['spacing' => 'one'],
        'declare_equal_normalize' => ['space' => 'single'],
        'declare_strict_types' => true,
        'dir_constant' => true,
        'ereg_to_preg' => true,
        'function_typehint_space' => true,
        'general_phpdoc_annotation_remove' => ['author', 'version', 'property'],
        'global_namespace_import' => ['import_classes' => false],
        'single_line_comment_style' => true,
        'include' => true,
        'indentation_type' => false,
        'is_null' => ['use_yoda_style' => false],
        'linebreak_after_opening_tag' => true,
        'lowercase_cast' => true,
        'magic_constant_casing' => true,
        'method_argument_space' => true,
        'method_separation' => true,
        'modernize_types_casting' => true,
        'native_function_casing' => true,
        'no_blank_lines_after_class_opening' => true,
        'no_blank_lines_after_phpdoc' => true,
        'no_empty_comment' => true,
        'no_empty_phpdoc' => true,
        'no_empty_statement' => true,
        'no_extra_consecutive_blank_lines' => true,
        'no_leading_import_slash' => true,
        'no_leading_namespace_whitespace' => true,
        'no_mixed_echo_print' => true,
        'no_short_bool_cast' => true,
        'no_singleline_whitespace_before_semicolons' => true,
        'no_spaces_around_offset' => true,
        'no_trailing_comma_in_list_call' => true,
        'no_trailing_comma_in_singleline_array' => true,
        'no_unneeded_control_parentheses' => true,
        'no_unused_imports' => true,
        'no_whitespace_before_comma_in_array' => true,
        'no_whitespace_in_blank_line' => true,
        'normalize_index_brace' => true,
        'object_operator_without_whitespace' => true,
        'ordered_imports' => true,
        'php_unit_construct' => true,
        'php_unit_dedicate_assert' => true,
        'phpdoc_indent' => true,
        'phpdoc_no_access' => true,
        'phpdoc_no_alias_tag' => true,
        'phpdoc_no_empty_return' => true,
        'phpdoc_no_package' => true,
        'phpdoc_no_useless_inheritdoc' => true,
        'phpdoc_return_self_reference' => true,
        'phpdoc_scalar' => true,
        'phpdoc_separation' => false,
        'phpdoc_single_line_var_spacing' => true,
        'phpdoc_to_comment' => true,
        'phpdoc_trim' => true,
        'phpdoc_types' => true,
        'pow_to_exponentiation' => true,
        'self_accessor' => false, // causes phpns to fail tests
        'short_scalar_cast' => true,
        'single_class_element_per_statement' => true,
        'space_after_semicolon' => ['remove_in_empty_for_expressions' => true],
        'standardize_not_equals' => true,
        'ternary_operator_spaces' => true,
        'trailing_comma_in_multiline_array' => true,
        'trim_array_spaces' => true,
        'unary_operator_spaces' => true,
        'visibility_required' => true,
        'whitespace_after_comma_in_array' => true,
        'array_syntax' => ['syntax' => 'short'],
        'list_syntax' => ['syntax' => 'short'],
        'combine_consecutive_issets' => true,
        'combine_consecutive_unsets' => true,
        'align_multiline_comment' => ['comment_type' => 'all_multiline'],
        'yoda_style' => false,
    ])
    ->setFinder($finder);

También hay otras automatizaciones adicionales aparte de PHP-CS-Fixer qué podemos usar para la sintaxis del código. Una de ellas es tener un fichero .editorconfig en la raíz de nuestro proyecto. EditorConfig ayuda a mantener estilos de codificación consistentes para varios desarrolladores que trabajan en el mismo proyecto en varios editores e IDE. Consiste en un formato de archivo para definir estilos de codificación.

Podríamos definir algo así:

# EditorConfig is awesome: http://EditorConfig.org

# top-most EditorConfig file
root = true

[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 4

[Makefile]
indent_style = tab

[*.php]
max_line_length = 200
ij_continuation_indent_size = 4
ij_php_align_assignments = false
ij_php_align_class_constants = false
ij_php_align_group_field_declarations = false
ij_php_align_inline_comments = false
ij_php_align_key_value_pairs = false
ij_php_align_multiline_array_initializer_expression = false
ij_php_align_multiline_binary_operation = false
ij_php_align_multiline_chained_methods = false
ij_php_align_multiline_extends_list = false
ij_php_align_multiline_for = true
ij_php_align_multiline_parameters = false
ij_php_align_multiline_parameters_in_calls = true
ij_php_align_multiline_ternary_operation = false
ij_php_align_phpdoc_comments = false
ij_php_align_phpdoc_param_names = false
ij_php_anonymous_brace_style = end_of_line
ij_php_api_weight = 28
ij_php_array_initializer_new_line_after_left_brace = true
ij_php_array_initializer_right_brace_on_new_line = true
ij_php_array_initializer_wrap = on_every_item
ij_php_assignment_wrap = off
ij_php_author_weight = 28
ij_php_binary_operation_sign_on_next_line = false
ij_php_binary_operation_wrap = off
ij_php_blank_lines_after_class_header = 0
ij_php_blank_lines_after_function = 1
ij_php_blank_lines_after_imports = 1
ij_php_blank_lines_after_opening_tag = 0
ij_php_blank_lines_after_package = 1
ij_php_blank_lines_around_class = 1
ij_php_blank_lines_around_constants = 0
ij_php_blank_lines_around_field = 0
ij_php_blank_lines_around_method = 1
ij_php_blank_lines_before_class_end = 0
ij_php_blank_lines_before_imports = 1
ij_php_blank_lines_before_method_body = 0
ij_php_blank_lines_before_package = 1
ij_php_blank_lines_before_return_statement = 1
ij_php_blank_lines_between_imports = 0
ij_php_block_brace_style = end_of_line
ij_php_call_parameters_new_line_after_left_paren = true
ij_php_call_parameters_right_paren_on_new_line = true
ij_php_call_parameters_wrap = on_every_item
ij_php_catch_on_new_line = false
ij_php_category_weight = 28
ij_php_class_brace_style = next_line
ij_php_comma_after_last_array_element = true
ij_php_concat_spaces = true
ij_php_copyright_weight = 28
ij_php_deprecated_weight = 28
ij_php_do_while_brace_force = always
ij_php_else_if_style = combine
ij_php_else_on_new_line = false
ij_php_example_weight = 28
ij_php_extends_keyword_wrap = off
ij_php_extends_list_wrap = off
ij_php_fields_default_visibility = private
ij_php_filesource_weight = 28
ij_php_finally_on_new_line = false
ij_php_for_brace_force = always
ij_php_for_statement_new_line_after_left_paren = false
ij_php_for_statement_right_paren_on_new_line = false
ij_php_for_statement_wrap = off
ij_php_force_short_declaration_array_style = true
ij_php_global_weight = 28
ij_php_group_use_wrap = on_every_item
ij_php_if_brace_force = always
ij_php_if_lparen_on_next_line = false
ij_php_if_rparen_on_next_line = false
ij_php_ignore_weight = 28
ij_php_import_sorting = alphabetic
ij_php_indent_break_from_case = true
ij_php_indent_case_from_switch = true
ij_php_indent_code_in_php_tags = false
ij_php_internal_weight = 28
ij_php_keep_blank_lines_after_lbrace = 0
ij_php_keep_blank_lines_before_right_brace = 0
ij_php_keep_blank_lines_in_code = 1
ij_php_keep_blank_lines_in_declarations = 0
ij_php_keep_control_statement_in_one_line = true
ij_php_keep_first_column_comment = true
ij_php_keep_indents_on_empty_lines = false
ij_php_keep_line_breaks = true
ij_php_keep_rparen_and_lbrace_on_one_line = true
ij_php_keep_simple_methods_in_one_line = false
ij_php_lambda_brace_style = end_of_line
ij_php_license_weight = 28
ij_php_line_comment_add_space = false
ij_php_line_comment_at_first_column = true
ij_php_link_weight = 28
ij_php_lower_case_boolean_const = true
ij_php_lower_case_keywords = true
ij_php_lower_case_null_const = true
ij_php_method_brace_style = next_line
ij_php_method_call_chain_wrap = off
ij_php_method_parameters_new_line_after_left_paren = true
ij_php_method_parameters_right_paren_on_new_line = true
ij_php_method_parameters_wrap = on_every_item
ij_php_method_weight = 28
ij_php_modifier_list_wrap = false
ij_php_multiline_chained_calls_semicolon_on_new_line = false
ij_php_namespace_brace_style = 1
ij_php_new_line_after_php_opening_tag = false
ij_php_null_type_position = in_the_end
ij_php_package_weight = 28
ij_php_param_weight = 0
ij_php_parentheses_expression_new_line_after_left_paren = false
ij_php_parentheses_expression_right_paren_on_new_line = false
ij_php_phpdoc_blank_line_before_tags = false
ij_php_phpdoc_blank_lines_around_parameters = false
ij_php_phpdoc_keep_blank_lines = true
ij_php_phpdoc_param_spaces_between_name_and_description = 1
ij_php_phpdoc_param_spaces_between_tag_and_type = 1
ij_php_phpdoc_param_spaces_between_type_and_name = 1
ij_php_phpdoc_use_fqcn = false
ij_php_phpdoc_wrap_long_lines = false
ij_php_place_assignment_sign_on_next_line = false
ij_php_place_parens_for_constructor = 0
ij_php_property_read_weight = 28
ij_php_property_weight = 28
ij_php_property_write_weight = 28
ij_php_return_type_on_new_line = false
ij_php_return_weight = 1
ij_php_see_weight = 28
ij_php_since_weight = 28
ij_php_sort_phpdoc_elements = true
ij_php_space_after_colon = true
ij_php_space_after_colon_in_return_type = true
ij_php_space_after_comma = true
ij_php_space_after_for_semicolon = true
ij_php_space_after_quest = true
ij_php_space_after_type_cast = true
ij_php_space_after_unary_not = false
ij_php_space_before_array_initializer_left_brace = false
ij_php_space_before_catch_keyword = true
ij_php_space_before_catch_left_brace = true
ij_php_space_before_catch_parentheses = true
ij_php_space_before_class_left_brace = true
ij_php_space_before_closure_left_parenthesis = true
ij_php_space_before_colon = true
ij_php_space_before_colon_in_return_type = false
ij_php_space_before_comma = false
ij_php_space_before_do_left_brace = true
ij_php_space_before_else_keyword = true
ij_php_space_before_else_left_brace = true
ij_php_space_before_finally_keyword = true
ij_php_space_before_finally_left_brace = true
ij_php_space_before_for_left_brace = true
ij_php_space_before_for_parentheses = true
ij_php_space_before_for_semicolon = false
ij_php_space_before_if_left_brace = true
ij_php_space_before_if_parentheses = true
ij_php_space_before_method_call_parentheses = false
ij_php_space_before_method_left_brace = true
ij_php_space_before_method_parentheses = false
ij_php_space_before_quest = true
ij_php_space_before_short_closure_left_parenthesis = true
ij_php_space_before_switch_left_brace = true
ij_php_space_before_switch_parentheses = true
ij_php_space_before_try_left_brace = true
ij_php_space_before_unary_not = false
ij_php_space_before_while_keyword = true
ij_php_space_before_while_left_brace = true
ij_php_space_before_while_parentheses = true
ij_php_space_between_ternary_quest_and_colon = false
ij_php_spaces_around_additive_operators = true
ij_php_spaces_around_arrow = false
ij_php_spaces_around_assignment_in_declare = true
ij_php_spaces_around_assignment_operators = true
ij_php_spaces_around_bitwise_operators = true
ij_php_spaces_around_equality_operators = true
ij_php_spaces_around_logical_operators = true
ij_php_spaces_around_multiplicative_operators = true
ij_php_spaces_around_null_coalesce_operator = true
ij_php_spaces_around_relational_operators = true
ij_php_spaces_around_shift_operators = true
ij_php_spaces_around_unary_operator = false
ij_php_spaces_around_var_within_brackets = false
ij_php_spaces_within_array_initializer_braces = false
ij_php_spaces_within_brackets = false
ij_php_spaces_within_catch_parentheses = false
ij_php_spaces_within_for_parentheses = false
ij_php_spaces_within_if_parentheses = false
ij_php_spaces_within_method_call_parentheses = false
ij_php_spaces_within_method_parentheses = false
ij_php_spaces_within_parentheses = false
ij_php_spaces_within_short_echo_tags = true
ij_php_spaces_within_switch_parentheses = false
ij_php_spaces_within_while_parentheses = false
ij_php_special_else_if_treatment = true
ij_php_subpackage_weight = 28
ij_php_ternary_operation_signs_on_next_line = false
ij_php_ternary_operation_wrap = off
ij_php_throws_weight = 2
ij_php_todo_weight = 28
ij_php_unknown_tag_weight = 28
ij_php_upper_case_boolean_const = false
ij_php_upper_case_null_const = false
ij_php_uses_weight = 28
ij_php_var_weight = 28
ij_php_variable_naming_style = camel_case
ij_php_version_weight = 28
ij_php_while_brace_force = always
ij_php_while_on_new_line = false

Análisis de código

PHPStan se enfoca en encontrar errores en nuestro código sin ejecutarlo realmente. Detecta clases enteras de errores incluso antes de escribir ningún test. Si se te ha olvidado el tipo de retorno en una función, o una variables que pasas no es del tipo correcto,… en el informe de PHPStan aparecerá todo esto más. Es de lo más configurable, tiene distintos niveles de análisis

En el caso que nos ocupa lo que hago es basarme en el código de otras librerías que ya han lo han dejado todo configurado a tope y yo puedo modificar un poco a mi gusto lo que quiera. PHPStan se basa en un fichero llamado phpstan.neon al igual que PHP-CS-Fixer lo mejor es tener este fichero en la raíz para que sea compartido por todos y para ejecutarlos solo tenemos que llamar a composer phpstan. A continuación podemos ver el fichero

includes:
    - vendor/phpstan/phpstan-phpunit/extension.neon
    - vendor/phpstan/phpstan-phpunit/rules.neon
    - vendor/ekino/phpstan-banned-code/extension.neon
    - vendor/korbeil/phpstan-generic-rules/extension.neon

parameters:
    tmpDir: var/cache/phpstan
    customRulesetUsed: true
    reportMagicMethods: true
    reportMagicProperties: true
    inferPrivatePropertyTypeFromConstructor: true
    autoload_directories: []
    excludes_analyse:
        - %currentWorkingDirectory%/var
    universalObjectCratesClasses:
        - PHPUnit\Framework\TestCase
    polluteCatchScopeWithTryAssignments: true
    reportUnmatchedIgnoredErrors: false
    checkMissingIterableValueType: false
    checkGenericClassInNonGenericObjectType: false
    ignoreErrors:
        -
            message: '#Unreachable statement - code above always terminates.#'
            path: tests/*

Testing

Esta parte es la más delicada, porque podemos tener tests unitarios, de integración, de aceptación y no siempre es necesario lanzarlos todos. Mi experiencia me dice que lo mejor es que los unitarios sean test rápidos sin dependencias externas y así podamos ejecutarlos en cada modificación. Los test de integración lo mejor sería ejecutarlos cada push o si estamos cambiando algo. Y por último los test de aceptación pues ejecutarlos si hemos cambiado algo de la capa más externa (un controlador). De cualquier forma lo normal es ejecutar todos los test en el pipeline de despliegue para estar seguro de que todo funciona para así por ejemplo poder crear la imagen de Docker que va a desplegarse 😉

Para evitar que los tests tengan dependencias unos de otros, es decir, que en el primer test creemos un registro en la BD, en el siguiente lo actualicemos y por ultimo en otro test lo borremos, podemos configurar el fichero phpunit.xml.dist en la raíz para que la ejecución sea random. Para ejecutar los test, al igual que hemos hecho con las otras herramientas, podemos tener un script en composer para que solo sea composer test

<?xml version="1.0" encoding="UTF-8"?>

<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
         colors="true"
         executionOrder="random"
>
    <php>
        <ini name="error_reporting" value="-1"/>
        <server name="APP_ENV" value="test" force="true"/>
    </php>

    <testsuites>
        <testsuite name="Project Test Suite">
            <directory>tests</directory>
        </testsuite>
    </testsuites>
</phpunit>

Esto del testing no acaba en PHPUnit, hay un campo muy amplio de herramientas que podemos utilizar para hacer que nuestro código esté más sano, por ejemplo

  • Mutation Testing
    Mutation testing es una técnica de prueba basada en fallas que proporciona un criterio de prueba llamado Mutation Score Indicator (MSI). El MSI se puede utilizar para medir la efectividad de un equipo de prueba en términos de su capacidad para detectar fallos. Dicho de otra manera lo que hacen librerías como https://github.com/infection/infection es «hackear tu código» cambiando por ejemplo condiciones > por >= o por < en if, cambiando valoren de retorno,… para así estar seguro de que tus test prueban al 100% tu código y que no hay ningún «mutante suelto».
    Del mismo modo que hemos hecho con el resto de librerías, podemos añadir un script para no tener que recordar todo el comando.
  • Code Coverage
    Es una medida utilizada para describir el porcentaje de código que está cubierto por los tests. Es una medida un tanto engañosa, ya que no por tener mucha cobertura tus test son mejores… Lo que si deberíamos de tener en cuenta es que si tenemos una cobertura por ejemplo del 75% y añadimos una nueva funcionalidad esa cobertura no baje de ese 75% (si baja es que quizás hallamos escrito pocos tests)… Si te interesa como automatizarlo, échale un ojo a https://ocramius.github.io/blog/automated-code-coverage-check-for-github-pull-requests-with-travis/

Comprobando la seguridad

La herramienta https://github.com/fabpot/local-php-security-checker basado en la línea de comandos que verifica si tu aplicación PHP depende de paquetes PHP con vulnerabilidades de seguridad conocidas. Utiliza Security Advisories Database en segundo plano. Otra opción podría ser que añadamos algún «bot» como dependabot que hace una PR cuando alguna de las librerías de nuestro proyecto se ha actualizado.

Con esto ya tenemos nuestra caja de herramientas llena de automatizaciones para varios ámbitos de nuestro proyecto. Ahora vamos con otra serie de automatizaciones que tienen que ver más con el IDE (PHPStorm en mi caso)

Automatizando el boilerplate

Con las librerías anteriores hemos visto como actualizar «al finalizar», es decir tengo un script que puedo ejecutar cuando he terminado un commit o cuando voy a hacer un push o cuando X, en este apartado vamos a ver una serie de automatizaciones para que nuestro día a día sea más sencillo:

Atajos de teclado

Quien me conoce sabe que soy un friki de los atajos de teclado, sobre todo en PHPStorm, esto no me hace un programador 10x ni mucho menos, pero hace mi día a día mucho más sencillo. Yo utilizo Key Promoter X porque me aparecen avisos cuando utilizo algo para que le añada un atajo de teclado. Además de atajos de teclado como estos también me parecen útiles.

Plantillas

Una manera sencilla de que todo empiece bien es tener las plantillas ajustadas a nuestro estilo de programación, por ejemplo haciendo que todas nuestras clases sean final, para ello en PHPStorm podemos ir a Preferences > Editor > File and Code Templates y allí editar las plantillas que queramos.

<?php
#parse("PHP File Header.php")

#if (${NAMESPACE})

namespace ${NAMESPACE};

#end

final class ${NAME} {

}

Esta es mi plantilla para clases. En la pestaña includes está editada para añadir declare(strict_types=1); así no se me olvida ponerlo 🙂

Inspections

Aunque tengamos instalado PHPStan y pasemos un análisis estático, es mucho más cómodo que el editor nos vaya avisando de las incongruencias/errores/gazapos que cometemos. Para que PHPStorm nos vaya ayudando en a medida que escribimos podemos es editar las inspecciones de código.

Inspecciones de PHPStorm

¿Y cuáles activo?¿Cuáles desactivo? Pues eso dependerá de nuestro proyecto, de nuestro estilo de programación, del framework. Para mí lo más importante es no agobiarse, añadimos unas cuantas y vemos si nos son útiles o no. Poco a poco tendremos las inspecciones a nuestro gusto.

PHPInspection

El plugin PHPInspection es un analizador de código estático al igual que PHPStan. Cubre problemas relacionados con las condiciones en los if, problemas de compatibilidad, uso de PHPUnit,… y lo mejor de todo es que lo hace desde el propio IDE y a medida que estamos escribiendo código. Del mismo modo que las inspecciones anteriores ¿qué chequeos activo? ¿Cuales no? pues eso dependerá de nuestro código, ya que hay algunos checks que son realmente útiles y otros demasiado exigentes. El mismo consejo que antes no te agobies activándolos todos. Lo mejor es que la documentación es genial, te explica porqué ese código que acabas de escribir puede mejorarse.

Conclusiones

Estos son solo algunas herramientas, seguro que hay muchas, que podemos ejecutar en nuestra máquina, en nuestra mano está automatizarlas con hooks de git y/o llevar todas estas herramientas/librerías a nuestro entorno de integración continua para conseguir todo esto de manera automática. Además otra de las cosas que conseguimos si nuestro pipeline es automático es evitar los olvidos (se me olvido pasar los test) y vencer a la pereza (PHPStan nos da 15 warnings y….) así que ánimo.

La idea de este post no es que nos pongamos como locos a meter con calzador todas estas librerías, templates,… sino que tengamos opciones dentro de nuestra «caja de herramientas» para mejorar la carga que llevamos en nuestra mochila. Sin tanta alegoría, la idea es que conozcamos una serie de herramientas y hagamos que nuestro día a día se centre en resolver problemas y no tanto en acordarnos de ejecutar este comando o la llave del if va en una nueva linea. De cualquier modo, lo único que me gustaría que te llevases de aquí es que no nos agobiemos con todos los cambios, sino que los vayamos aplicando de manera progresiva.

Si te sigue interesando el tema hace tiempo que ya hablamos de como sacarle partido a PHPStorm, atajos de teclado en PHPStorm, o de cómo refactorizar usando PHPStorm

2 respuestas a “Automatizando para pensar en el problema y no en recordar comandos cuando programamos en PHP”

  1. Avatar de ciltocruz
    ciltocruz

    Hola, Jesús.

    Por si alguien llega por aquí… que mire la configuración de la versión 3.0 de CS-Fixer ya que la configuración que está en este post sólo sirve para la versión 2.
    https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/3.0/doc/config.rst

    ¡Saludos!

    Me gusta

    1. Avatar de jesuslc

      Gracias po
      R la actualización

      Me gusta

Comenta la entrada

Este sitio utiliza Akismet para reducir el spam. Conoce cómo se procesan los datos de tus comentarios.

Jesús López

Soy un Ingeniero en Informática y apasionado de la programación. Me gusta disfrutar de mi familia, viajar y perdernos paseando.  Me mola programar, hacer tests y refactorizar código . Practico Test Driven Development (TDD) y me lo paso bien con el legacy codeLeer más

Sígueme en: