Q:

Problema ao adicionar mês a uma data com php

estou com um certo problema ao adicionar meses com php, tinha feito usando o modify mas como na própria documentação já informa que da erro, dai tentei outras 3 funções que encontrei e dai as 3 me trazem o mesmo erro, quando uma data inicia nos dias 29, 30 ou 31 de janeiro, por exemplo, no mês de fevereiro vem todos para o dia 28 (até ai ok), mas nos outros meses (março, abril) deveria vir para cada dia criado (29, 30 ou 31) e não sempre dia 28.
Como posso resolver isso?
Segue um exemplo com uma dessas funções:
$date=new DateTime();
$date->setDate(2017,1,31);

addMonths($date, 1);
echo $date->format('d/m/Y');

echo "<br>";

addMonths($date, 1);
echo $date->format('d/m/Y');

echo "<br>";

addMonths($date, 1);
echo $date->format('d/m/Y');

function addMonths($date,$months)
{
    $init=clone $date;
    $modifier=$months.' months';
    $back_modifier =-$months.' months';

    $date->modify($modifier);
    $back_to_init= clone $date;
    $back_to_init->modify($back_modifier);

    while($init->format('m')!=$back_to_init->format('m')){
        $date->modify('-1 day')    ;
        $back_to_init= clone $date;
        $back_to_init->modify($back_modifier);
    }
}

resultado 
28/02/2017
28/03/2017
28/04/2017

enquanto o resultado esperado seria
28/02/2017
31/03/2017
30/04/2017

A:

Resumindo, o problema é que você está alterando a instância original da data inicial, então, desta forma, quando você adiciona 1 mês à data inicial, está será 28/02, isto é, $date passará a ser 28/02; quando adicionado mais um mês, o dia será 28/03, pois estaria adicionando um mês em 28/02 e não dois meses em 31/01. Para não alterar o objeto, clone o objeto de entrada e modifique-o, retornando sua instância ao final:
function add_months(DateTime $date, int $months)
{
    // Clona o objeto $date para mantê-lo inalterado
    $future = clone $date;

    // Define o modificador
    $modifier = "{$months} months";

    // Modifica a data $future
    $future->modify($modifier);

    // Clona o objeto $future para corrigir o limite dos dias
    $pass = clone $future;
    $pass->modify("-{$modifier}");

    // Enquanto o mes atual for diferente do mês do passado do futuro
    while ($date->format('m') != $pass->format('m'))
    {
        // Modifica as datas em -1 dia
        $future->modify("-1 day");
        $pass->modify("-1 day");
    }

    // Retorna a data desejada
    return $future;
}

// Define a data inicial
$date = new DateTime();
$date->setDate(2017, 1, 31);

// Adiciona 1 mês à data inicial
echo add_months($date, 1)->format("d/m/Y"), PHP_EOL;

// Adiciona 2 meses à data inicial
echo add_months($date, 2)->format("d/m/Y"), PHP_EOL;

// Adiciona 3 meses à data inicial
echo add_months($date, 3)->format("d/m/Y"), PHP_EOL;

Desta forma, o resultado produzido será o esperado:
28/02/2017
31/03/2017
30/04/2017

Perceba que, ao invés de adicionar várias vezes 1 mês, você deverá adicionar a quantidade correta de meses, senão o problema persistirá.

