Migrating Your PHP Application from Twilio SDK 4.x to 5.x

Deprecation notice: New functionality will only be added to the new libraries (PHP 5.x). The old libraries (PHP 4.x) are deprecated and Twilio will no longer provide bug fixes. Support might ask you to upgrade before debugging issues.

The Twilio PHP SDK has undergone significant changes from version 4.x to 5.x - we'll break down the major changes here to make migrating to the new version as painless as possible. If you're integrating Twilio in your PHP app for the first time, you can skip straight to the install page.

PHP Version Compatibility

The 5.x version of the Twilio SDK is compatible with PHP versions 5.3 and higher. As of August 2016, it is recommended that you upgrade your applications to at least PHP 5.6 to receive the latest security updates.

Namespaces

The new SDK takes advantage of PHP namespaces for proper autoloading. This means classes are no longer prepended by "Services_" or contain long class names as they did in version 4.x of the SDK. After the 5.x SDK has been autoloaded, you will be able to use namespaces as in the following example.

<?php
// Composer autoload file
require_once '/path/to/vendor/autoload.php';
use Twilio\Rest\Client;

Utility classes (used to generate TwiML, or mint auth tokens for Video or Twilio Client) have also been refactored in this way. Check out the generated API reference doc to browse the available namespaces.

Accessing REST API Resources

The way you interact with REST API resources in the 5.x version of the SDK is also significantly changed (we believe improved) from version 4.x. The abstraction in the 4.x API over REST API resources sometimes resulted in inefficient network requests, occasionally making 2 or 3 API requests when only one would have been necessary. The 5.x SDK introduces two new concepts to address this.

  • Resource Context: A reference to a resource in the REST API that has not yet been operated on or fetched
  • Resource Instance: A representation of a resource that has been retrieved from the API after some operation has been performed

Consider the following example from the IP Messaging REST API.

<?php
require '/path/to/vendor/autoload.php';
use Twilio\Rest\Client;

// Create REST API Client
$sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$token = 'your_auth_token';
$client = new Client($sid, $token);

// 1.) Service instance context
$service = $client->ipMessaging->services('ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');

// 2.) Channel context
$channelContext = $service->channels('CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');

// 3.) Channel instance
$channel = $channelContext->fetch();
echo $channel->friendlyName;

Let's break down what happened in the code above, by the numbers.

  1. We create a "context" for the IP Messaging service instance we'd like to operate on. We know its SID ahead of time. No HTTP requests have been made to the API.
  2. We create a "context" for the actual IP Messaging channel we'd like to retrieve from the API. We know its SID ahead of time also. Still, no HTTP requests have been made.
  3. Finally, we use "fetch" to return an instance of a channel resource from the API. Under the covers, this makes an HTTP GET request to the REST API. The $channel object returned is populated with properties of the channel, retrieved from the Twilio back end.

In the 4.x helper library, this type of interaction would have cost two HTTP requests - one to fetch the service instance, and another to fetch the channel. This is a fluent interface, so you can chain these method calls together if desired.

<?php
require '/path/to/vendor/autoload.php';
use Twilio\Rest\Client;

// Create REST API Client
$sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$token = 'your_auth_token';
$client = new Client($sid, $token);

// All together now!
$channel = $client->ipMessaging
    ->services('ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
    ->channels('CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
    ->fetch();

echo $channel->friendlyName;

Creating and deleting resources work in a similar way - you can see examples of each type of operation in the API docs.

Listing and Paging Resources

Getting lists of resources from the API follows a similar pattern, this time using the "read" method.

<?php
require '/path/to/vendor/autoload.php';
use Twilio\Rest\Client;

// Create REST API Client
$sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$token = 'your_auth_token';
$client = new Client($sid, $token);

// Get a list of channels
$channels = $client->ipMessaging
    ->services('ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
    ->channels
    ->read();

// List ALL the channels
foreach ($channels as $channel) {
    echo $channel->friendlyName;
}

To page through larger result sets, you can use the "stream" method, which returns an iterator that will transparently loop through all the possible results for your resource context, even if there are more results than the (configurable up to 1,000) page size.

<?php
require '/path/to/vendor/autoload.php';
use Twilio\Rest\Client;

// Create REST API Client
$sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$token = 'your_auth_token';
$client = new Client($sid, $token);

// Get a stream of channels
$channelStream = $client->ipMessaging
    ->services('ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
    ->channels
    ->stream();

// List ALL the channels
foreach ($channelStream as $channel) {
    echo $channel->friendlyName;
}

Passing Arguments to the API

When passing query parameters for a "read" operation or adding parameters for a "create" or "update", you'll notice differences from 4.x to 5.x as well. All universally required parameters for an operation are positional - all other parameters (including required parameters where either one value or another may be passed, like a text message "Body" or "MediaUrl") are passed in an array.

Consider the following example of sending a text message (creating a Message resource). The only argument that is always required is a "To" phone number. Two more arguments are required:

  • Either a "From" phone number or a "MessagingServiceSid"
  • Either (or both of) a "Body" and a "MediaUrl"

The code to do this is the following.

<?php
require_once '/path/to/vendor/autoload.php';
use Twilio\Rest\Client;

// Create a client with your Account SID and Auth Token from twilio.com/console
$sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$token = 'your_auth_token';
$client = new Client($sid, $token);

$client->messages->create(
    '+15558675309',
    array(
        'from' => '+15017250604',
        'body' => 'Hey Jenny! Good luck on the bar exam!',
        'mediaUrl' => 'http://farm2.static.flickr.com/1075/1404618563_3ed9a44a3a.jpg',
    )
);

Here's an example of querying for calls that were completed between midnight July 4th, 2009 and midnight July 6th, 2009.

<?php
require_once '/path/to/vendor/autoload.php';
use Twilio\Rest\Client;

// Create a client with your Account SID and Auth Token from twilio.com/console
$sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$token = 'your_auth_token';
$client = new Client($sid, $token);

// Read an array of calls from the REST API between two dates
$calls = $client->calls->read(
    array(
        'status' => 'completed',
        'starttimeAfter' => '2009-07-04',
        'starttimeBefore' => '2009-07-06'
    )
);

// Loop over the list of calls and echo a property for each one
foreach ($calls as $call) {
    echo $call->to;
}

TwiML Generation

You can now chain your calls to output simple TwiML like so:

<?php
require_once './vendor/autoload.php';
use Twilio\Twiml;

$response = new Twiml();
$response->say('Hello!');
$response->hangup();

echo $response;

You can find any voice verbs available as a method of a Response instance. And you can set any attributes for those verbs using keyword arguments. All of them are using the underscore notation.

Loading Code Samples...
Language
SDK Version:
  • 5.x
Format:
  • TwiML
<?php
require_once './vendor/autoload.php';
use Twilio\Twiml;

$response = new Twiml();
$response->say('Chapeau!', ['voice' => 'alice', 'language' => 'fr-FR']);

echo $response;
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Say voice="alice" language="fr-FR">Chapeau!</Say>
</Response>
Simple voice response saying "Chapeau!" in french

Notice that you can nest verbs this way:

Loading Code Samples...
Language
SDK Version:
  • 5.x
Format:
  • TwiML
<?php
require_once './vendor/autoload.php';
use Twilio\Twiml;

$response = new Twiml();
$gather = $response->gather(['action' => '/process_gather.php',
    'method' => 'GET']);
$gather->say('Enter something, or not');
$response->redirect('/process_gather.php?Digits=TIMEOUT', ['method' => 'GET']);

echo $response;
<?xml version="1.0" encoding="UTF-8"?>
<!-- page located at http://example.com/gather_hints.xml -->
<Response>
    <Gather action="/process_gather.php" method="GET">
        <Say>Enter something, or not</Say>
    </Gather>
    <Redirect method="GET">
        /process_gather.php?Digits=TIMEOUT
    </Redirect>
</Response>
Gather with Redirect

The same changes apply to Messages Responses:

Loading Code Samples...
Language
SDK Version:
  • 5.x
Format:
  • TwiML
<?php
require_once './vendor/autoload.php';
use Twilio\Twiml;

$response = new Twiml();
$response->message('Store Location: 123 Easy St.');

echo $response;
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Message>
        Store Location: 123 Easy St.
    </Message>
</Response>
Simple sending of SMS

And a nested example:

Loading Code Samples...
Language
SDK Version:
  • 5.x
Format:
  • TwiML
<?php
require_once './vendor/autoload.php';
use Twilio\Twiml;

$response = new Twiml();
$message = $response->message();
$message->body('Store Location: 123 Easy St.');
$message->media('https://demo.twilio.com/owl.png');

echo $response;
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Message>
        <Body>Store Location: 123 Easy St.</Body>
        <Media>https://demo.twilio.com/owl.png</Media>
    </Message>
</Response>
Sending of an Message with Media (MMS)

The REST API documentation contains a listing of required parameters, and code samples for every API operation.

Exceptions

Twilio Client

In version 4.x, client authentication issues were handled with the generic Services_Twilio_RestException and only after you try to make a call to a Twilio API.

<?php
require_once('/path/to/twilio-php/Services/Twilio.php'); // Loads the library

$sid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
$token = "your_auth_token";
$client = new Services_Twilio($sid, $token);

try {
    call = $client->account->calls
                  ->get("CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");

    echo $call->to;
}
catch (Services_Twilio_RestException $e){
  echo $e.get_code();
}

In version 5.x you see that authentication exceptions can be handled when initializing the client and catching the ConfigurationException.

<?php
require_once('/path/to/twilio-php/Services/Twilio.php'); // Loads the library

use Twilio\Exceptions\ConfigurationException;
use Twilio\Rest\Client;

$sid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
$token = "your_auth_token";

try {
    $client = new Client($sid, $token);
}
catch (ConfigurationException $e){
  echo $e.get_code();
}

call = $client->account->calls
              ->get("CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");

echo $call->to;

CurlClient

When initializing the curl client you will see the EnvironmentException if curl is not installed on your system.

<?php
require_once('/path/to/twilio-php/Services/Twilio.php'); // Loads the library

use Twilio\Exceptions\TwilioException;
use Twilio\Http\CurlClient;

$sid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
$token = "your_auth_token";
$client = new Client($sid, $token);

try {
  $client = new CurlClient();

  $client->options(
            'GET',
            'http://api.twilio.com',
            array(),
            array(),
            array(),
            $sid,
            $token
        );
}
catch (EnvironmentException $e){
    echo $e.get_code();
}

echo $call->to;

TwilioException

TwilioException can be used to handle API errors as shown below. It replaces Services_Twilio_RestException from version 4.x.

<?php
require_once('/path/to/twilio-php/Services/Twilio.php'); // Loads the library

use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Client;

$sid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
$token = "your_auth_token";
$client = new Client($sid, $token);

try {
    call = $client->account->calls
                  ->get("CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
}
catch (TwilioException $e){
    echo $e.get_code();
}

echo $call->to;

TwimlException

When building twiml, if it does not conform to what the API expects, you will see TwimlException instead of Services_Twilio_TwimlException and can be handled as follows:

<?php
require_once './vendor/autoload.php';
use Twilio\Twiml;

try {
  $response = new Twiml();
  $dial = $response->dial();
  $dial->conference('Room 1234');
  echo $response;
}
catch (TwimlException $e) {
  echo $e
}

Debugging API Requests

To assist with debugging, the library allows you to access the underlying request and response objects, including all the headers. This capability is built into the default HTTP client that ships with the library.

For example, if you are trying to track down the source of latency, you can retrieve the custom Twilio header Twilio-Request-Duration to see how long in seconds the request took to process on our platform:

<?php 

require_once '/path/to/vendor/autoload.php';
use Twilio\Rest\Client;

$sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$token = 'your_auth_token';
$client = new Client($sid, $token);

$message = $client->messages->create("+14158675309", array(
  'From' => "+14258675310",
  'Body' => 'Ahoy!'
));

// Retrieve the last response from the HTTP client and inspect the Twilio-Request-Duration header
echo($client->getHttpClient()->lastResponse->getHeaders()["Twilio-Request-Duration"]);

Getting Help

We'd love to hear your feedback on the PHP SDK, and help you past any issues you may encounter. Feel free to drop us a line, and we'll make sure to get you sorted!

Need some help?

We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd browsing the Twilio tag on Stack Overflow.

Loading Code Samples...
SDK Version:
  • 5.x
Format:
  • TwiML
<?php
require_once './vendor/autoload.php';
use Twilio\Twiml;

$response = new Twiml();
$response->say('Chapeau!', ['voice' => 'alice', 'language' => 'fr-FR']);

echo $response;
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Say voice="alice" language="fr-FR">Chapeau!</Say>
</Response>
SDK Version:
  • 5.x
Format:
  • TwiML
<?php
require_once './vendor/autoload.php';
use Twilio\Twiml;

$response = new Twiml();
$gather = $response->gather(['action' => '/process_gather.php',
    'method' => 'GET']);
$gather->say('Enter something, or not');
$response->redirect('/process_gather.php?Digits=TIMEOUT', ['method' => 'GET']);

echo $response;
<?xml version="1.0" encoding="UTF-8"?>
<!-- page located at http://example.com/gather_hints.xml -->
<Response>
    <Gather action="/process_gather.php" method="GET">
        <Say>Enter something, or not</Say>
    </Gather>
    <Redirect method="GET">
        /process_gather.php?Digits=TIMEOUT
    </Redirect>
</Response>
SDK Version:
  • 5.x
Format:
  • TwiML
<?php
require_once './vendor/autoload.php';
use Twilio\Twiml;

$response = new Twiml();
$response->message('Store Location: 123 Easy St.');

echo $response;
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Message>
        Store Location: 123 Easy St.
    </Message>
</Response>
SDK Version:
  • 5.x
Format:
  • TwiML
<?php
require_once './vendor/autoload.php';
use Twilio\Twiml;

$response = new Twiml();
$message = $response->message();
$message->body('Store Location: 123 Easy St.');
$message->media('https://demo.twilio.com/owl.png');

echo $response;
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Message>
        <Body>Store Location: 123 Easy St.</Body>
        <Media>https://demo.twilio.com/owl.png</Media>
    </Message>
</Response>