php - How to extract constructor parameters from object? - Stack Overflow

admin2025-04-17  6

I am trying to extract the constructor parameters from an object so I can pass them as arguments to a different function.

$args = $object->getConstructorParams();
some_func(...$args);

I don't have access to the definition of some_func. I can define the object class myself, I would prefer it to be and abstract class. The core of the problem is that child classes might have different construct arguments. I was thinking something along the lines of

abstract class mom
{
    private $args;
    public function __construct(...$args)
    {
        $this->args = $args;
    }
    public function getConstructorParams()
    {
        return $this->args;
    }
}

class child extends mom
{
    public $name;
    public function __construct($name)
    {
        parent::__construct($name);
        $this->name = $name;
    }
}

But that puts a lot of pressure on the right implementation of the constructor in the daughter classes. Is there a more elegant way to achieve something similar?

I have looked at get_object_vars, but the object can have a ton of parameters that are not necessarily all passed to the constructor. I Have also looked at ReflectionClass::getConstructor() and ReflectionFunctionAbstract::getParameters() but this only seems to be able to get the names of parameters and not the actual values. Combining both get_object_vars and the relfections comes a long way, but would miss passed arguments if they are not stored directly in the object.

I am trying to extract the constructor parameters from an object so I can pass them as arguments to a different function.

$args = $object->getConstructorParams();
some_func(...$args);

I don't have access to the definition of some_func. I can define the object class myself, I would prefer it to be and abstract class. The core of the problem is that child classes might have different construct arguments. I was thinking something along the lines of

abstract class mom
{
    private $args;
    public function __construct(...$args)
    {
        $this->args = $args;
    }
    public function getConstructorParams()
    {
        return $this->args;
    }
}

class child extends mom
{
    public $name;
    public function __construct($name)
    {
        parent::__construct($name);
        $this->name = $name;
    }
}

But that puts a lot of pressure on the right implementation of the constructor in the daughter classes. Is there a more elegant way to achieve something similar?

I have looked at get_object_vars, but the object can have a ton of parameters that are not necessarily all passed to the constructor. I Have also looked at ReflectionClass::getConstructor() and ReflectionFunctionAbstract::getParameters() but this only seems to be able to get the names of parameters and not the actual values. Combining both get_object_vars and the relfections comes a long way, but would miss passed arguments if they are not stored directly in the object.

Share edited Mar 8 at 1:09 Dharman 33.5k27 gold badges101 silver badges148 bronze badges Recognized by PHP Collective asked Jan 31 at 12:26 SenneVPSenneVP 13510 bronze badges 4
  • 1 Just a note, deriving from a base class form a so-called "IS A" relationship. An instance of the derived class is an instance of the base class, too. Applied to your example above, a "child" is a "mum" but not every "mum" also is a "child", which is exactly opposite to common use of those two terms. – Ulrich Eckhardt Commented Jan 31 at 12:33
  • 4 Your last limitation is very fundamental - there is absolutely no guarantee that an object stores its constructor arguments anywhere. Nor is there any guarantee that passing the same constructor parameters will result in an identical object. For example, a constructor might take a minimum and maximum, and generate a random value between them. So I wonder if there's an X/Y problem here: what are you actually trying to achieve? – IMSoP Commented Jan 31 at 12:37
  • 3 Class hierarchy must not be the object hierarchy. That is you have two trees. Use factories that know how to arrange constructor parameters and create those objects. What you ask for is doing this in reverse, that means you are implementing it anyway but without the injection. Make your factory methods static if that helps you to get started. Use dependency injection so that you have fine-grained control to configure the overall composition. – hakre Commented Jan 31 at 12:40
  • 1 @IMSoP: Given constructor parameters wrapped in a function (but this idea is a bit late right now for me), when using PHP 8.4, there is php.net/manual/en/reflectionclass.newlazyghost.php - it could be static the callable. Just saying. – hakre Commented Jan 31 at 13:37
Add a comment  | 

1 Answer 1

Reset to default 1

Asking for the constructor parameters is a key thing here. You are actually looking for parameters.

Make the class representing those parameters and delegate the relationship to actual objects.

Example:

readonly class person
{
    public function __construct(private string $name, private ?person $parent) {}
}


$mom   = new person('mom', null);
assert($mom instanceof person);

$child = new person('child', $mom);
assert($child instanceof person);

Not every mum is a child, well, actually they are all persons (or whatever, humans love simplification and object orientation is just an example of that, a box for everything and the world is alright).

Demo

You only benefit from an abstraction if it is really abstract (leaving things out, defer the details), otherwise you have to implement everything and for that you would use code-generation (and then traits).


And then:

I don't have access to the definition of some_func [but to the classes]

Again, we can inject the function as well, as if it would be a parameter.

Some made-up example, but often calling a functions mean we want to (or can) switch context/category (similar as in math):

readonly class person
{
    // ...
    public function export(closure $replacer)
    {
        return $replacer(random_int(-21, 20), ucfirst($this->name));
    }
}

And that in the action:

// the following three dots "..." dot-dot-dot are NOT an omission
$result = $child->export(some_func(...));
assert(is_some_from_func($result));

Don't ask for things (parameters), just inject and implement. The things continue to compute without much break. And it remains easy to refactor and test.

转载请注明原文地址:http://www.anycun.com/QandA/1744862175a88668.html