[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
<?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));
}
}