[GH-ISSUE #129] PHP question - How to wrap every call to Spotify in try-catch #77

Closed
opened 2026-02-27 19:25:55 +03:00 by kerem · 6 comments
Owner

Originally created by @kasperkamperman on GitHub (Jun 11, 2018).
Original GitHub issue: https://github.com/jwilsson/spotify-web-api-php/issues/129

I think it might be smart if I wrap every call I make in a try-catch, so I can detect errors (rate-limit, expired accesToken). Like shown in this closed issue: https://github.com/jwilsson/spotify-web-api-php/issues/72

I'm aware that this is more a lack in my PHP knowledge than an issue with this API, however I think maybe more people would like "save" calls, so the answer can be useful for others as well.

An example call that I'd like to wrap would be:

$playlist = $api->getUserPlaylist($userId, $playlistId, $options)

I was think to make a function like callSpotify and then pass the call. However I'm in doubt how to pass the parameters, because I only could find example to functions without parameters.

callSpotify(getUserPlaylist($userId, $playlistId, $options));

function callSpotify($callFunction) {
  try {
     $api->$callFunction();
  } 
  catch (\Exception $e) {
    echo $e->getMessage()."\n";
  }

Originally created by @kasperkamperman on GitHub (Jun 11, 2018). Original GitHub issue: https://github.com/jwilsson/spotify-web-api-php/issues/129 I think it might be smart if I wrap every call I make in a try-catch, so I can detect errors (rate-limit, expired accesToken). Like shown in this closed issue: https://github.com/jwilsson/spotify-web-api-php/issues/72 I'm aware that this is more a lack in my PHP knowledge than an issue with this API, however I think maybe more people would like "save" calls, so the answer can be useful for others as well. An example call that I'd like to wrap would be: ``` $playlist = $api->getUserPlaylist($userId, $playlistId, $options) ``` I was think to make a function like callSpotify and then pass the call. However I'm in doubt how to pass the parameters, because I only could find example to functions without parameters. ``` callSpotify(getUserPlaylist($userId, $playlistId, $options)); function callSpotify($callFunction) { try { $api->$callFunction(); } catch (\Exception $e) { echo $e->getMessage()."\n"; } ```
kerem closed this issue 2026-02-27 19:25:55 +03:00
Author
Owner

@jwilsson commented on GitHub (Jun 12, 2018):

Hi!
Try something like this:

function callSpotify($callFunction, $args) {
    try {
        return call_user_func_array($callFunction, $args);
    }
    catch (\Exception $e) {
        echo $e->getMessage()."\n";
    }
}

callSpotify(
    array($api, 'getUserPlaylist'),
    array($userId, $playlistId),
);

That will let you pass any method and any number of arguments to it.

<!-- gh-comment-id:396461818 --> @jwilsson commented on GitHub (Jun 12, 2018): Hi! Try something like this: ```php function callSpotify($callFunction, $args) { try { return call_user_func_array($callFunction, $args); } catch (\Exception $e) { echo $e->getMessage()."\n"; } } callSpotify( array($api, 'getUserPlaylist'), array($userId, $playlistId), ); ``` That will let you pass any method and any number of arguments to it.
Author
Owner

@kasperkamperman commented on GitHub (Jun 12, 2018):

Thanks. I'll try it out.

<!-- gh-comment-id:396633997 --> @kasperkamperman commented on GitHub (Jun 12, 2018): Thanks. I'll try it out.
Author
Owner

@andersborgabiro commented on GitHub (Jun 13, 2018):

I do that systematically for all the calls, and in all cases I present my own messages, a la "Failed retrieving album xxxxxx" etc, instead of generic messages.

<!-- gh-comment-id:396907640 --> @andersborgabiro commented on GitHub (Jun 13, 2018): I do that systematically for all the calls, and in all cases I present my own messages, a la "Failed retrieving album xxxxxx" etc, instead of generic messages.
Author
Owner

@kasperkamperman commented on GitHub (Jun 14, 2018):

Maybe for archiving purposes in case someone else runs across this. The function I've ended up with:

function callSpotify($method, $args) {

	global $api;
	global $currentRefreshToken;
	global $currentAccessTokenFn;

	// try-catch
	// https://github.com/jwilsson/spotify-web-api-php/issues/129#issuecomment-396461818
	// https://stackoverflow.com/questions/18526060/why-should-one-prefer-call-user-func-array-over-regular-calling-of-function
	try {
		return call_user_func_array(array($api, $method), $args);
	} 
	catch (\Exception $e) {

		$exeptionCode = $e->getCode();
		//echo $e->getMessage()."\n";

		// The access token expired or Invalid access token
		if($e->getCode() == 401) { 
			//echo $e->getMessage();
			
			// Obtain new accessToken
			$session = new SpotifyWebAPI\Session(
			    '<app client_id>', // app client_id
			    '<app client_secret>'  // app client_secret
			);

			$session->refreshAccessToken($currentRefreshToken);

	    	$accessToken = $session->getAccessToken();

			// store the newly received token
			$api->setAccessToken($accessToken);
	   		file_put_contents($currentAccessTokenFn, $accessToken);
			   
			// do the call again
			callSpotify($method, $args);
		}
		else if ($e->getCode() == 429) { // 429 is Too Many Requests
			$lastResponse = $api->getRequest()->getLastResponse(); // Note "getRequest()" since $api->getLastResponse() won't be set
			
			// Number of seconds to wait before sending another request, round up
			$retryAfter = $lastResponse['headers']['Retry-After']+1;

			sleep($retryAfter);
			callSpotify($method, $args);
		} 
		else {
			// Some other kind of error
			echo $e->getMessage();

			return null;
		}

	}
}

Called like:

$options = ['market' => $userPlaylist['targetMarket'], 'limit' => 1];
//$results = $api->search($query, 'track', $options);
$results = callSpotify('search',array($query, 'track', $options));
<!-- gh-comment-id:397253748 --> @kasperkamperman commented on GitHub (Jun 14, 2018): Maybe for archiving purposes in case someone else runs across this. The function I've ended up with: ``` function callSpotify($method, $args) { global $api; global $currentRefreshToken; global $currentAccessTokenFn; // try-catch // https://github.com/jwilsson/spotify-web-api-php/issues/129#issuecomment-396461818 // https://stackoverflow.com/questions/18526060/why-should-one-prefer-call-user-func-array-over-regular-calling-of-function try { return call_user_func_array(array($api, $method), $args); } catch (\Exception $e) { $exeptionCode = $e->getCode(); //echo $e->getMessage()."\n"; // The access token expired or Invalid access token if($e->getCode() == 401) { //echo $e->getMessage(); // Obtain new accessToken $session = new SpotifyWebAPI\Session( '<app client_id>', // app client_id '<app client_secret>' // app client_secret ); $session->refreshAccessToken($currentRefreshToken); $accessToken = $session->getAccessToken(); // store the newly received token $api->setAccessToken($accessToken); file_put_contents($currentAccessTokenFn, $accessToken); // do the call again callSpotify($method, $args); } else if ($e->getCode() == 429) { // 429 is Too Many Requests $lastResponse = $api->getRequest()->getLastResponse(); // Note "getRequest()" since $api->getLastResponse() won't be set // Number of seconds to wait before sending another request, round up $retryAfter = $lastResponse['headers']['Retry-After']+1; sleep($retryAfter); callSpotify($method, $args); } else { // Some other kind of error echo $e->getMessage(); return null; } } } ``` Called like: ``` $options = ['market' => $userPlaylist['targetMarket'], 'limit' => 1]; //$results = $api->search($query, 'track', $options); $results = callSpotify('search',array($query, 'track', $options)); ```
Author
Owner

@kasperkamperman commented on GitHub (Feb 24, 2019):

Sorry to 'open' this up again. I'm using the callSpotify function like this to obtain a new accessToken and then I'll recursively call it again (with the updated accessToken). However if I call it recursively the function doesn't return anything, while there is data.

I tried several things. I've declared a variable outside the try-catch block however I can't seem to access the data outside this block.

I'm using PHP 7.3. I came across some topics on StackOverflow that try/catch works a bit different, however I can't seem to find what's going on.

I hope someone has a clue.

$options = ['fields' => 'name, snapshot_id, tracks.total']; 
$sp_playlist_details = callSpotify($api, $creds, 'getPlaylist',array($playlist['sp_playlist_id'], $options));
// so $sp_playlist_details stays empty when I have an expired wrong accessToken. While I thought I had solved this by resursively calling callSpotify after getting the right token. 

function callSpotify(&$api, &$spotifyAuth, $method, $args) {

// what I set inside try doesn't seem outside the try-catch
// $returnedFromSpotify = null;

try {
        
   $returnedFromSpotify = call_user_func_array(array($api, $method), $args);

   echo '<br/>return inside try: <br/>';
   var_dump($returnedFromSpotify);

   // this return works when callSpotify is called externally (1st time)
   // when this function is called recursively from the catch statement below (after obtaining a new accessToken)
   // the values are not returned and it stays empty, will there is data...

   return $returnedFromSpotify;
} 
catch (\Exception $e) {

        $exeptionCode = $e->getCode();
        echo 'received error message :'.$e->getMessage()."\n";

        // The access token expired or Invalid access token
        if($exeptionCode == 401) { 
            
            $client_id     = '<my_client_id>';
            $client_secret = '<my_client_secret>';
           
            // Obtain new accessToken
            $session = new SpotifyWebAPI\Session($client_id, $client_secret);
            
            $session->refreshAccessToken($spotifyAuth['sp_refresh_token']);

            $spotifyAuth['sp_access_token'] = $session->getAccessToken();
 
            // store the newly received token
            echo 'set changed access token in callSpotify: '.$spotifyAuth['sp_access_token'];
            $api->setAccessToken($spotifyAuth['sp_access_token']);

            unset($session);
            $session = NULL;
               
            // to debug
            echo 'before calling again after exception and new token --------------- <br/>API:<br/>';
            print_r($api);
            echo '<br/>spotifyAuth: <br/>';
            print_r($spotifyAuth);
            echo '<br/>method: <br/>';
            print_r($method);
            echo '<br/>args: <br/>';
            print_r($args);

            // this call works, however the value returned after this function is evoked after this exception is always empty. 
            callSpotify($api, $spotifyAuth, $method, $args);
        }
        else if ($exeptionCode == 429) { // 429 is Too Many Requests
            
            //if($debug) echo $e->getCode();
            $lastResponse = $api->getRequest()->getLastResponse(); // Note "getRequest()" since $api->getLastResponse() won't be set
            
            // Number of seconds to wait before sending another request, round up
            $retryAfter = $lastResponse['headers']['Retry-After']+1;

            sleep($retryAfter);
            callSpotify($api, $spotifyAuth, $method, $args);
        } 
        else {
            // Some other kind of error
            echo 'other error?';
            echo $e->getMessage();
            return null;
        }

    }
};
<!-- gh-comment-id:466774160 --> @kasperkamperman commented on GitHub (Feb 24, 2019): Sorry to 'open' this up again. I'm using the callSpotify function like this to obtain a new accessToken and then I'll recursively call it again (with the updated accessToken). However if I call it recursively the function doesn't return anything, while there is data. I tried several things. I've declared a variable outside the try-catch block however I can't seem to access the data outside this block. I'm using PHP 7.3. I came across some topics on StackOverflow that try/catch works a bit different, however I can't seem to find what's going on. I hope someone has a clue. ``` $options = ['fields' => 'name, snapshot_id, tracks.total']; $sp_playlist_details = callSpotify($api, $creds, 'getPlaylist',array($playlist['sp_playlist_id'], $options)); // so $sp_playlist_details stays empty when I have an expired wrong accessToken. While I thought I had solved this by resursively calling callSpotify after getting the right token. function callSpotify(&$api, &$spotifyAuth, $method, $args) { // what I set inside try doesn't seem outside the try-catch // $returnedFromSpotify = null; try { $returnedFromSpotify = call_user_func_array(array($api, $method), $args); echo '<br/>return inside try: <br/>'; var_dump($returnedFromSpotify); // this return works when callSpotify is called externally (1st time) // when this function is called recursively from the catch statement below (after obtaining a new accessToken) // the values are not returned and it stays empty, will there is data... return $returnedFromSpotify; } catch (\Exception $e) { $exeptionCode = $e->getCode(); echo 'received error message :'.$e->getMessage()."\n"; // The access token expired or Invalid access token if($exeptionCode == 401) { $client_id = '<my_client_id>'; $client_secret = '<my_client_secret>'; // Obtain new accessToken $session = new SpotifyWebAPI\Session($client_id, $client_secret); $session->refreshAccessToken($spotifyAuth['sp_refresh_token']); $spotifyAuth['sp_access_token'] = $session->getAccessToken(); // store the newly received token echo 'set changed access token in callSpotify: '.$spotifyAuth['sp_access_token']; $api->setAccessToken($spotifyAuth['sp_access_token']); unset($session); $session = NULL; // to debug echo 'before calling again after exception and new token --------------- <br/>API:<br/>'; print_r($api); echo '<br/>spotifyAuth: <br/>'; print_r($spotifyAuth); echo '<br/>method: <br/>'; print_r($method); echo '<br/>args: <br/>'; print_r($args); // this call works, however the value returned after this function is evoked after this exception is always empty. callSpotify($api, $spotifyAuth, $method, $args); } else if ($exeptionCode == 429) { // 429 is Too Many Requests //if($debug) echo $e->getCode(); $lastResponse = $api->getRequest()->getLastResponse(); // Note "getRequest()" since $api->getLastResponse() won't be set // Number of seconds to wait before sending another request, round up $retryAfter = $lastResponse['headers']['Retry-After']+1; sleep($retryAfter); callSpotify($api, $spotifyAuth, $method, $args); } else { // Some other kind of error echo 'other error?'; echo $e->getMessage(); return null; } } }; ```
Author
Owner

@kasperkamperman commented on GitHub (Feb 24, 2019):

Ok, I found the bug of not returning. In the catch statement I did callSpotify, but I forgot to return the value.

callSpotify($api, $spotifyAuth, $method, $args);

should be

return callSpotify($api, $spotifyAuth, $method, $args);

Still wondering though why a variable that will be modified in try-catch is not accessible outside it.

<!-- gh-comment-id:466807468 --> @kasperkamperman commented on GitHub (Feb 24, 2019): Ok, I found the bug of not returning. In the catch statement I did callSpotify, but I forgot to **return** the value. ``` callSpotify($api, $spotifyAuth, $method, $args); ``` should be ``` return callSpotify($api, $spotifyAuth, $method, $args); ``` Still wondering though why a variable that will be modified in try-catch is not accessible outside it.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/spotify-web-api-php#77
No description provided.