Pimple ArgumentCountError: Too few arguments to function

1.1k views Asked by At

I'm trying to understand dependency injection, and I in theory, I get it, but, I wanted to make an example just to help me. However, I'm getting the following error

PHP Fatal error:  Uncaught ArgumentCountError: Too few arguments to function Main\Services\UserService::__construct(), 0 passed
in ...

Here's my "main" file, I've called it index.php

<?php 
#index.php
require_once 'vendor/autoload.php';

use Main\Controllers\UserController;
use Main\Services\UserService;
use Main\Models\UserModel;
use Pimple\Container;

$container = new Container;
$container['UserModel'] = function($c) {
    return new UserModel();
};

$container['UserService'] = function ($c) {
    return new UserService($c['UserModel']);
};

$container['UserController'] = function ($c) {
    echo "creating a new UserController\n";

    $aUserService = $c['UserService'];
    return new UserController($aUserService);
};

$myUserService = new $container['UserService'];
$myResult = $myUserService->parseGet();
echo $myResult, PHP_EOL;

Here's the model that's being passed into the service

<?php
# Models/UserModel.php
namespace Main\Models;

class UserModel
{
    private $record;

    public function getRecord()
    {
        return [
            'first_name' => 'Bob',
            'last_name'  => 'Jones',
            'email'      => '[email protected]',
            'date_joined' => '11-12-2014',
        ];
    }
}

And, here's the service, which takes the model as it's constructor argument

<?php
namespace Main\Services;

use Main\Models\UserModel;

class UserService
{
    private $userModel;

    public function __construct(UserModel $userModel)
    {
        echo "verifying that the userModel passed in was a valid UserModel\n";
        $this->userModel = $userModel;

         print_r($this->userModel->getRecord());
    }

    public function parseGet()
    {
        $retVal = $this->userModel->getRecord();

        return json_encode($retVal);
    }
}

So, in theory, Pimple should be able to instantiate a UserService object. I even verified that the UserModel passed into the UserService class is a valid UserModel object (which it is as is evident that it prints out an array)

What am I missing? Is there something that I have failed to account for?

Oh, here's the composer.json file

{
    "require": {
        "pimple/pimple": "~3.0"
    },
    "autoload": {
        "psr-4": {
            "Main\\" : "./"
        }
    }
}

I made a gitHub link so the project can be checked out and ran without having to copy past everything (https://github.com/gitKearney/pimple-example)

SOLUTION

The problem was I have an extra new in the line

$myUserService = new $container['UserService'];

It was so obvious, I couldn't see it

2

There are 2 answers

1
Adam Cameron On BEST ANSWER

$container['UserService'] already is a UserService object. check yer service definition:

$container['UserService'] = function ($c) {
    return new UserService($c['UserModel']);
};

That sets $container['UserService'] to be return new UserService($c['UserModel']) when it's invoked, right?

Your code is basically going:

$o1 = new UserService($c['UserModel']);
$o2 = new $o2;
2
Nima On

You use dependency injection containers to free yourself form the pain of manipulating objects' dependencies. Creating a new UserService is not necessary (if it really is a service). In that case, you define it in your $container once, and use it whenever you need to.

So instead of creating a new UserService object and calling its method parseGet() (what you did in your code) you can do something like this:

$myResult = $container['UserService']->parseGet();

When you define something like:

$container['UserService'] = function ($c) {
    return new UserService($c['UserModel']);
};

you are telling Pimple how to handle creation of a UserService once you try to access $container['UserService']

That's why you define dependencies as functions.

This might be related to your question Why use a closure for assignment instead of directly assigning a value to a key?