<p dir="auto"><strong>Symfony version(s) affected</strong>: 4.0.6</p>
<p dir="auto"><strong>Description</strong><br>
So, let's say I have a JSON data corresponding to a class <strong>Child</strong> that has an attribute <strong>games</strong> that is an array of objects of class <strong>Game</strong>. So when using the serialisation using setters I get and the end a Child Object with an attribute games that is an array of several Game instances.<br>
However for design reasons it is not possible to use the setters so I had to use the serialisation through the constructor, hence on my constructor I have someting like:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="
class Child
{

/**
     * @var Game[]
     */
    private $games;

   /**
     * Child constructor.
     *
     * @param Game[] $games
     */
    public function __construct(
        array $games,
    ) {
        $this-&gt;games = $games;
    }
 }"><pre class="notranslate"><code class="notranslate">
class Child
{

/**
     * @var Game[]
     */
    private $games;

   /**
     * Child constructor.
     *
     * @param Game[] $games
     */
    public function __construct(
        array $games,
    ) {
        $this-&gt;games = $games;
    }
 }
</code></pre></div>
<h3 dir="auto"><strong>setter denormalization</strong></h3>
<p dir="auto">The problem here is that the denormalizer could not figure out that the games is an array of objects from the class <strong>Game</strong> and then I get instead of an object an array have the same attributes defined on the <strong>Game</strong> class which is not the same when I add a setter for the games.</p>
<p dir="auto">When I debug it the code fro both setter serialization and constructor serialization  I can see the difference between both methods getting into action.</p>
<ul dir="auto">
<li>For the first case of the <strong>setter denormalization</strong> the function <strong>validateAndDenormalize</strong> from the <strong>AbstractObjectNormalizer</strong> is handling the normalization and there is the code there is a check on the collection type   <code class="notranslate">if ($type-&gt;isCollection() &amp;&amp; null !== ($collectionValueType = $type-&gt;getCollectionValueType()) &amp;&amp; Type::BUILTIN_TYPE_OBJECT === $collectionValueType-&gt;getBuiltinType())</code> which can determine if the array has objects from a defined class.</li>
</ul>
<p dir="auto">Adding a setter like that is enough to get the right denormalization:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="      /**
      * @param Game[] $games
      * @return Child
     */
     public function setGames(array $games): Child
     {
         $this-&gt;games = $games;
        return $this;
     }"><pre class="notranslate"><code class="notranslate">      /**
      * @param Game[] $games
      * @return Child
     */
     public function setGames(array $games): Child
     {
         $this-&gt;games = $games;
        return $this;
     }
</code></pre></div>
<h3 dir="auto"><strong>constructor denormalization</strong></h3>
<ul dir="auto">
<li>However for the other case: the <strong>constructor denormalization</strong>: the function <strong>instatiateObject</strong> from the <strong>AbstractNormalizer</strong> class is being executed and there there are no check on the type collection  <code class="notranslate">$params[] = $parameterData;</code> ==&gt; that line exactly is responsible of giving me back an array of attributes instead of creating an object from the class <strong>Game</strong> which I really found a bad behaviour and mis-leading.</li>
</ul>
<p dir="auto"><strong>How to reproduce</strong><br>
Just setting a Child class with an attribute games which is an array of Game objects. And a class Game with some attributes. And then A Json Object that represents a child objects with a related array of games is enough to reproduces this behaviour.<br>
A hint for the JSON:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{
	&quot;name&quot;: &quot;test-boy&quot;,
	&quot;age&quot;: 12,
	&quot;games&quot;: [{
		&quot;name&quot;: &quot;Age of Empire&quot;,
		&quot;genre&quot;: &quot;Strategy&quot;
	}]

}"><pre class="notranslate"><code class="notranslate">{
	"name": "test-boy",
	"age": 12,
	"games": [{
		"name": "Age of Empire",
		"genre": "Strategy"
	}]

}
</code></pre></div>
<p dir="auto"><strong>Possible Solution</strong><br>
The possible solution is to implement a collection verification as it is implemented on the first case (setter denormalization) would be enough I guess to fix this behaviour.</p>
<table role="table">
<thead>
<tr>
<th>Q</th>
<th>A</th>
</tr>
</thead>
<tbody>
<tr>
<td>Bug report?</td>
<td>no</td>
</tr>
<tr>
<td>Feature request?</td>
<td>yes</td>
</tr>
<tr>
<td>BC Break report?</td>
<td>no</td>
</tr>
<tr>
<td>RFC?</td>
<td>no</td>
</tr>
<tr>
<td>Symfony version</td>
<td>?</td>
</tr>
</tbody>
</table>
<p dir="auto">Currenly PhpDocExtractor works only with class properties. It's not possible to clarify the type of the constructor parameter through docblock comment.</p>
<div class="highlight highlight-text-html-php notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="class A
{
    private $b;

    /**
     * @param B[] $b
     */
    public function __construct(array $b)
    {
        $this-&gt;b = $b;
    }

    public function getB()
    {
        return $this-&gt;b;
    }
}

class B
{
    private $c;

    public function __construct($c)
    {
        $this-&gt;c = $c;
    }

    public function getC()
    {
        return $this-&gt;c;
    }
}

$a = $serializer-&gt;denormalize(['b' =&gt; [['c' =&gt; 1], ['c' =&gt; 2], ['c' =&gt; 3]]], A::class);
print_r($a);"><pre class="notranslate"><span class="pl-k">class</span> <span class="pl-v">A</span>
{
    <span class="pl-k">private</span> <span class="pl-c1"><span class="pl-c1">$</span>b</span>;

    <span class="pl-c">/**</span>
<span class="pl-c">     * @param B[] $b</span>
<span class="pl-c">     */</span>
    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">__construct</span>(<span class="pl-smi">array</span> <span class="pl-s1"><span class="pl-c1">$</span>b</span>)
    {
        <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">b</span> = <span class="pl-s1"><span class="pl-c1">$</span>b</span>;
    }

    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">getB</span>()
    {
        <span class="pl-k">return</span> <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">b</span>;
    }
}

<span class="pl-k">class</span> <span class="pl-v">B</span>
{
    <span class="pl-k">private</span> <span class="pl-c1"><span class="pl-c1">$</span>c</span>;

    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">__construct</span>(<span class="pl-s1"><span class="pl-c1">$</span>c</span>)
    {
        <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">c</span> = <span class="pl-s1"><span class="pl-c1">$</span>c</span>;
    }

    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">getC</span>()
    {
        <span class="pl-k">return</span> <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">c</span>;
    }
}

<span class="pl-s1"><span class="pl-c1">$</span>a</span> = <span class="pl-s1"><span class="pl-c1">$</span>serializer</span>-&gt;<span class="pl-en">denormalize</span>([<span class="pl-s">'b'</span> =&gt; [[<span class="pl-s">'c'</span> =&gt; <span class="pl-c1">1</span>], [<span class="pl-s">'c'</span> =&gt; <span class="pl-c1">2</span>], [<span class="pl-s">'c'</span> =&gt; <span class="pl-c1">3</span>]]], <span class="pl-v">A</span>::class);
print_r(<span class="pl-s1"><span class="pl-c1">$</span>a</span>);</pre></div>
<p dir="auto">Expected result:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="App\A Object
(
    [b:App\A:private] =&gt; Array
        (
            [0] =&gt; App\B Object
                (
                    [c:App\B:private] =&gt; 1
                )
            [1] =&gt; App\B Object
                (
                    [c:App\B:private] =&gt; 2
                )
            [2] =&gt; App\B Object
                (
                    [c:App\B:private] =&gt; 3
                )
        )
)"><pre class="notranslate"><code class="notranslate">App\A Object
(
    [b:App\A:private] =&gt; Array
        (
            [0] =&gt; App\B Object
                (
                    [c:App\B:private] =&gt; 1
                )
            [1] =&gt; App\B Object
                (
                    [c:App\B:private] =&gt; 2
                )
            [2] =&gt; App\B Object
                (
                    [c:App\B:private] =&gt; 3
                )
        )
)
</code></pre></div>
<p dir="auto">Actual result:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="App\A Object
(
    [b:App\A:private] =&gt; Array
        (
            [0] =&gt; Array
                (
                    [c] =&gt; 1
                )
            [1] =&gt; Array
                (
                    [c] =&gt; 2
                )
            [2] =&gt; Array
                (
                    [c] =&gt; 3
                )
        )
)"><pre class="notranslate"><code class="notranslate">App\A Object
(
    [b:App\A:private] =&gt; Array
        (
            [0] =&gt; Array
                (
                    [c] =&gt; 1
                )
            [1] =&gt; Array
                (
                    [c] =&gt; 2
                )
            [2] =&gt; Array
                (
                    [c] =&gt; 3
                )
        )
)
</code></pre></div>