[PHP] Modifying a private class property at runtime

Published on 2019-12-03 • Modified on 2020-02-03

In this snippet, we will see how to read and modify a private property of a PHP object. I recently had a concrete case when I have created my EasyDeploy configuration. I had to modify a private property of the DefaultConfiguration object to make it work for my environment.
[Edit 2020-02-03] Added unit tests and better bool display.


<?php

declare(strict_types=1);

namespace App\Controller\Snippet;

use Symfony\Component\HttpFoundation\Request;

/**
 * I am using a PHP trait to isolate each snippet in a file.
 * This code should be called from a Symfony controller extending AbstractController (as of Symfony 4.2)
 * or Symfony\Bundle\FrameworkBundle\Controller\Controller (Symfony <= 4.1).
 * Services are injected in the main controller constructor.
 */
trait Snippet61Trait
{
    public function snippet61(Request $request): void
    {
        $class = \get_class($request);
        echo sprintf('> Request value object class: %s'.PHP_EOL, $class);

        // This code "$request->isHostValid" would provoke a PHP error as the "isHostValid"
        // is private (check out the unit tests)

        $property = (new \ReflectionClass($request))->getProperty('isHostValid');
        $property->setAccessible(true); // now we can read and write "isHostValid"
        echo '> isHostValid: '.((bool) $property->getValue($request) ? 'true' : 'false').PHP_EOL;

        $property->setValue($request, false);
        echo '> isHostValid: '.((bool) $property->getValue($request) ? 'true' : 'false');

        // That's it! 😁
    }
}

 Run this snippet  ≪ this.showUnitTest ? this.trans.hide_unit_test : this.trans.show_unit_test ≫  More on Stackoverflow   Read the doc  Random snippet

  Work with me!

<?php

declare(strict_types=1);

namespace App\Tests\Integration\Controller\Snippets;

use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\HttpFoundation\Request;

/**
 * @see Snippet74Trait
 */
final class Snippet61Test extends KernelTestCase
{
    /**
     * @see Snippet61Trait::snippet61
     */
    public function testSnippet61(): void
    {
        $request = Request::create('/en/snippets/modifying-a-private-class-property-at-runtime');
        $property = (new \ReflectionClass($request))->getProperty('isHostValid');

        // As of PHP 8.1, private properties are accessible with reflection!
        // @see https://phpbackend.com/blog/post/php-8-1-accessing-private-protected-properties-methods-via-reflection-api-is-now-allowed-without-calling-setAccessible
        if (PHP_VERSION_ID < 80100) {
            try {
                self::assertNull($property->getValue($request));
                self::fail('A ReflectionException should be raised!');
            } /* @noinspection PhpRedundantCatchClauseInspection */
            catch (\ReflectionException) {
            }
        }

        $property->setAccessible(true);
        self::assertTrue($property->getValue($request));
        $property->setValue($request, false);
        self::assertFalse($property->getValue($request));
    }
}