Bypass PHP’s visibility rules with Spatie’s invade package - simple closures let you read, write, and call private members for testing or deep integration. By Freek Van der Herten.

The article details a practical technique for breaching PHP’s private visibility barriers using the spatie/invade library. It begins by presenting a concrete example of a class with private properties and methods, then shows how direct access would normally trigger a fatal error. The solution is an invade() function that returns an Invader wrapper.

Historically, the wrapper relied on PHP’s Reflection API: it would instantiate a ReflectionClass, locate the desired property or method, make it accessible via setAccessible(true), and retrieve or assign values. While functional, this approach required per‑access Reflection objects and explicit accessibility toggling. The breakthrough came from recognizing that private visibility is confined to the class definition itself; any code executing within that class can access all private members of any instance, regardless of which object owns them.

By crafting closures that are executed with Closure::call($targetObject), the closure’s $this context and scope are rebound to the target object, placing the closure’s code inside the class’s scope and thereby granting it privileged access. The current Invader class embodies this concept in just three magic methods: __get creates a closure to read a property, __set assigns a value, and __call invokes a private method with any arguments. Each closure is immediately executed with ->call($this->obj), seamlessly bypassing visibility checks without Reflection.

The author notes that while powerful, invade should be reserved for scenarios where direct access is indispensable, such as test suites or deep‑integration libraries. Nice one!

[Read More]

Tags php app-development software-architecture infosec programming