Skip to content

Commit

Permalink
PHP7 Compat
Browse files Browse the repository at this point in the history
Retains PHP5 compat through several ifdef checks for ZEND_ENGINE_2/ZEND_ENGINE_3
When we're ready to drop PHP5 support, this code can be cleaned up noticably.
  • Loading branch information
sgolemon committed Aug 25, 2016
1 parent 163a858 commit 1b6d14d
Show file tree
Hide file tree
Showing 18 changed files with 685 additions and 330 deletions.
576 changes: 354 additions & 222 deletions mosquitto.c

Large diffs are not rendered by default.

278 changes: 214 additions & 64 deletions mosquitto_message.c

Large diffs are not rendered by default.

84 changes: 74 additions & 10 deletions php_mosquitto.h
Expand Up @@ -36,8 +36,14 @@ extern zend_module_entry mosquitto_module_entry;

#include <mosquitto.h>

#if defined(ZEND_ENGINE_2) && defined(ZTS)
# define MOSQUITTO_NEED_TSRMLS
#endif

typedef struct _mosquitto_client_object {
#ifndef ZEND_ENGINE_3
zend_object std;
#endif
struct mosquitto *client;

zend_fcall_info connect_callback;
Expand All @@ -55,24 +61,60 @@ typedef struct _mosquitto_client_object {
zend_fcall_info log_callback;
zend_fcall_info_cache log_callback_cache;

int looping;
int looping;

#ifdef ZTS
#ifdef MOSQUITTO_NEED_TSRMLS
TSRMLS_D;
#endif
#ifdef ZEND_ENGINE_3
zend_object std; /* Must be last */
#endif
} mosquitto_client_object;

typedef struct _mosquitto_message_object {
#ifndef ZEND_ENGINE_3
zend_object std;
#endif
struct mosquitto_message message;
zend_bool owned_topic;
zend_bool owned_payload;
#ifdef ZTS
#ifdef MOSQUITTO_NEED_TSRMLS
TSRMLS_D;
#endif
#ifdef ZEND_ENGINE_3
zend_object std; /* Must be last */
#endif
} mosquitto_message_object;

static inline
mosquitto_client_object *mosquitto_client_object_from_zend_object(zend_object* obj) {
return (mosquitto_client_object*)(
((char*)obj) - XtOffsetOf(mosquitto_client_object, std)
);
}

static inline
zend_object *mosquitto_client_object_to_zend_object(mosquitto_client_object* client) {
return &(client->std);
}

static inline
mosquitto_message_object *mosquitto_message_object_from_zend_object(zend_object* obj) {
return (mosquitto_message_object*)(
((char*)obj) - XtOffsetOf(mosquitto_message_object, std)
);
}

static inline
zend_object *mosquitto_message_object_to_zend_object(mosquitto_message_object* msg) {
return &(msg->std);
}

#ifdef ZEND_ENGINE_3
typedef int (*php_mosquitto_read_t)(mosquitto_message_object *mosquitto_object, zval *retval);
#else
typedef int (*php_mosquitto_read_t)(mosquitto_message_object *mosquitto_object, zval **retval TSRMLS_DC);
#endif
typedef int (*php_mosquitto_write_t)(mosquitto_message_object *mosquitto_object, zval *newval TSRMLS_DC);

typedef struct _php_mosquitto_prop_handler {
Expand All @@ -89,16 +131,31 @@ typedef struct _php_mosquitto_prop_handler {
#define PHP_MOSQUITTO_RESTORE_ERRORS() \
zend_restore_error_handling(&MQTTG(mosquitto_original_error_handling) TSRMLS_CC)


#define PHP_MOSQUITTO_FREE_CALLBACK(CALLBACK) \
#ifdef ZEND_ENGINE_3
# define PHP_MOSQUITTO_FREE_CALLBACK(client, CALLBACK) \
if (ZEND_FCI_INITIALIZED(client->CALLBACK ## _callback)) { \
zval_ptr_dtor(&client->CALLBACK ## _callback.function_name); \
} \
\
if (client->CALLBACK ## _callback.object != NULL) { \
zval tmp_; \
ZVAL_OBJ(&tmp_, client->CALLBACK ## _callback.object); \
zval_ptr_dtor(&tmp_); \
} \
client->CALLBACK ## _callback = empty_fcall_info; \
client->CALLBACK ## _callback_cache = empty_fcall_info_cache;
#else
# define PHP_MOSQUITTO_FREE_CALLBACK(client, CALLBACK) \
if (ZEND_FCI_INITIALIZED(client->CALLBACK ## _callback)) { \
zval_ptr_dtor(&client->CALLBACK ## _callback.function_name); \
} \
\
if (client->CALLBACK ## _callback.object_ptr != NULL) { \
zval_ptr_dtor(&client->CALLBACK ## _callback.object_ptr); \
}

} \
client->CALLBACK ## _callback = empty_fcall_info; \
client->CALLBACK ## _callback_cache = empty_fcall_info_cache;
#endif

#define PHP_MOSQUITTO_MESSAGE_PROPERTY_ENTRY_RECORD(name) \
{ "" #name "", sizeof("" #name "") - 1, php_mosquitto_message_read_##name, php_mosquitto_message_write_##name }
Expand All @@ -113,13 +170,20 @@ typedef struct _php_mosquitto_prop_handler {
} \
}

#define PHP_MOSQUITTO_MESSAGE_LONG_PROPERTY_READER_FUNCTION(name) \
static int php_mosquitto_message_read_##name(mosquitto_message_object *mosquitto_object, zval **retval TSRMLS_DC) \
{ \
#ifdef ZEND_ENGINE_3
# define PHP_MOSQUITTO_MESSAGE_LONG_PROPERTY_READER_FUNCTION(name) \
static int php_mosquitto_message_read_##name(mosquitto_message_object *mosquitto_object, zval *retval) { \
ZVAL_LONG(retval, mosquitto_object->message.name); \
return SUCCESS; \
}
#else
# define PHP_MOSQUITTO_MESSAGE_LONG_PROPERTY_READER_FUNCTION(name) \
static int php_mosquitto_message_read_##name(mosquitto_message_object *mosquitto_object, zval **retval TSRMLS_DC) { \
MAKE_STD_ZVAL(*retval); \
ZVAL_LONG(*retval, mosquitto_object->message.name); \
return SUCCESS; \
}
#endif

#define PHP_MOSQUITTO_MESSAGE_LONG_PROPERTY_WRITER_FUNCTION(name) \
static int php_mosquitto_message_write_##name(mosquitto_message_object *mosquitto_object, zval *newval TSRMLS_DC) \
Expand Down
4 changes: 2 additions & 2 deletions tests/Client/connect.phpt
Expand Up @@ -106,8 +106,8 @@ Mosquitto\Client::connect() expects at least 1 parameter, 0 given
%s error.
%s error.
Invalid function arguments provided.
Mosquitto\Client::connect() expects parameter 2 to be long, object given
Mosquitto\Client::connect() expects parameter 3 to be long, object given
Mosquitto\Client::connect() expects parameter 2 to be %s, object given
Mosquitto\Client::connect() expects parameter 3 to be %s, object given
%s error.
object(Mosquitto\Client)#%d (%d) {
}
Expand Down
7 changes: 4 additions & 3 deletions tests/Client/onConnect.phpt
Expand Up @@ -9,8 +9,10 @@ include(dirname(__DIR__) . '/setup.php');
try {
$client = new Mosquitto\Client;
$client->onConnect('foo');
} catch (Exception $e) {
} catch (TypeError $e) {
printf("Caught %s with code %d and message: %s\n", get_class($e), $e->getCode(), $e->getMessage());
} catch (Mosquitto\Exception $e) {
printf("Caught TypeError with code %d and message: %s\n", get_class($e), $e->getCode(), $e->getMessage());
}
unset($client);

Expand All @@ -26,8 +28,7 @@ for ($i = 0; $i < 2; $i++) {
}
?>
--EXPECTF--
Caught error 4096 (Argument 1 passed to Mosquitto\Client::onConnect() must be callable, string given) in %s on line 6
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::onConnect() expects parameter 1 to be a valid callback, function 'foo' not found or invalid function name
%ACaught TypeError with code 0 and message: %s
array(2) {
[0]=>
int(0)
Expand Down
7 changes: 4 additions & 3 deletions tests/Client/onDisconnect.phpt
Expand Up @@ -9,8 +9,10 @@ include(dirname(__DIR__) . '/setup.php');
try {
$client = new Mosquitto\Client;
$client->onDisconnect('foo');
} catch (Exception $e) {
} catch (TypeError $e) {
printf("Caught %s with code %d and message: %s\n", get_class($e), $e->getCode(), $e->getMessage());
} catch (Mosquitto\Exception $e) {
printf("Caught TypeError with code %d and message: %s\n", get_class($e), $e->getCode(), $e->getMessage());
}
unset($client);

Expand Down Expand Up @@ -47,8 +49,7 @@ for ($i = 0; $i < 5; $i++) {

?>
--EXPECTF--
Caught error 4096 (Argument 1 passed to Mosquitto\Client::onDisconnect() must be callable, string given) in %s on line 6
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::onDisconnect() expects parameter 1 to be a valid callback, function 'foo' not found or invalid function name
%ACaught TypeError with code 0 and message: %s
Triggering disconnect
Disconnected
Disconnected
7 changes: 4 additions & 3 deletions tests/Client/onLog.phpt
Expand Up @@ -13,8 +13,10 @@ function logger() {
try {
$client = new Mosquitto\Client;
$client->onLog('foo');
} catch (Exception $e) {
} catch (TypeError $e) {
printf("Caught %s with code %d and message: %s\n", get_class($e), $e->getCode(), $e->getMessage());
} catch (Mosquitto\Exception $e) {
printf("Caught TypeError with code %d and message: %s\n", get_class($e), $e->getCode(), $e->getMessage());
}

$client = new Mosquitto\Client;
Expand All @@ -26,8 +28,7 @@ $client->loop(50);
$client->loop(50);
?>
--EXPECTF--
Caught error 4096 (Argument 1 passed to Mosquitto\Client::onLog() must be callable, string given) in %s on line %d
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::onLog() expects parameter 1 to be a valid callback, function 'foo' not found or invalid function name
%ACaught TypeError with code 0 and message: %s
object(Mosquitto\Client)#%d (%d) {
}
array(2) {
Expand Down
9 changes: 5 additions & 4 deletions tests/Client/onMessage.phpt
Expand Up @@ -9,8 +9,10 @@ include(dirname(__DIR__) . '/setup.php');
try {
$client = new Mosquitto\Client;
$client->onMessage('foo');
} catch (Exception $e) {
} catch (TypeError $e) {
printf("Caught %s with code %d and message: %s\n", get_class($e), $e->getCode(), $e->getMessage());
} catch (Mosquitto\Exception $e) {
printf("Caught TypeError with code %d and message: %s\n", get_class($e), $e->getCode(), $e->getMessage());
}
unset($client);

Expand All @@ -28,15 +30,14 @@ $client2 = new Mosquitto\Client;
$client2->connect(TEST_MQTT_HOST);
$client2->publish('test', 'test', 1);

for ($i = 0; $i < 3; $i++) {
for ($i = 0; $i < 30; $i++) {
$client->loop(50);
$client2->loop(50);
}

?>
--EXPECTF--
Caught error 4096 (Argument 1 passed to Mosquitto\Client::onMessage() must be callable, string given) in %s on line %d
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::onMessage() expects parameter 1 to be a valid callback, function 'foo' not found or invalid function name
%ACaught TypeError with code 0 and message: %s
object(Mosquitto\Client)#%d (%d) {
}
object(Mosquitto\Message)#%d (%d) {
Expand Down
7 changes: 4 additions & 3 deletions tests/Client/onSubscribe.phpt
Expand Up @@ -9,8 +9,10 @@ include(dirname(__DIR__) . '/setup.php');
try {
$client = new Mosquitto\Client;
$client->onSubscribe('foo');
} catch (Exception $e) {
} catch (TypeError $e) {
printf("Caught %s with code %d and message: %s\n", get_class($e), $e->getCode(), $e->getMessage());
} catch (Mosquitto\Exception $e) {
printf("Caught TypeError with code %d and message: %s\n", get_class($e), $e->getCode(), $e->getMessage());
}
unset($client);

Expand All @@ -29,8 +31,7 @@ $client->loopForever();

?>
--EXPECTF--
Caught error 4096 (Argument 1 passed to Mosquitto\Client::onSubscribe() must be callable, string given) in %s on line 6
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::onSubscribe() expects parameter 1 to be a valid callback, function 'foo' not found or invalid function name
%ACaught TypeError with code 0 and message: %s
array(3) {
[0]=>
int(1)
Expand Down
7 changes: 4 additions & 3 deletions tests/Client/onUnsubscribe.phpt
Expand Up @@ -9,8 +9,10 @@ include(dirname(__DIR__) . '/setup.php');
try {
$client = new Mosquitto\Client;
$client->onUnsubscribe('foo');
} catch (Exception $e) {
} catch (TypeError $e) {
printf("Caught %s with code %d and message: %s\n", get_class($e), $e->getCode(), $e->getMessage());
} catch (Mosquitto\Exception $e) {
printf("Caught TypeError with code %d and message: %s\n", get_class($e), $e->getCode(), $e->getMessage());
}
unset($client);

Expand All @@ -34,8 +36,7 @@ $client->loopForever();

?>
--EXPECTF--
Caught error 4096 (Argument 1 passed to Mosquitto\Client::onUnsubscribe() must be callable, string given) in %s on line 6
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::onUnsubscribe() expects parameter 1 to be a valid callback, function 'foo' not found or invalid function name
%ACaught TypeError with code 0 and message: %s
array(3) {
[0]=>
int(1)
Expand Down
2 changes: 1 addition & 1 deletion tests/Client/publish.phpt
Expand Up @@ -114,7 +114,7 @@ Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::publish()
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::publish() expects parameter 1 to be string, object given
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::publish() expects at least 2 parameters, 1 given
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::publish() expects at least 2 parameters, 1 given
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::publish() expects parameter 3 to be long, object given
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::publish() expects parameter 3 to be %s, object given
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::publish() expects parameter 4 to be boolean, object given
Caught Mosquitto\Exception with code 0 and message: The client is not currently connected.
Caught Mosquitto\Exception with code 0 and message: The client is not currently connected.
Expand Down
4 changes: 2 additions & 2 deletions tests/Client/setMaxInFlightMessages.phpt
Expand Up @@ -37,5 +37,5 @@ object(Mosquitto\Client)#%d (0) {
}
object(Mosquitto\Client)#%d (0) {
}
string(87) "Mosquitto\Client::setMaxInFlightMessages() expects parameter 1 to be long, string given"
string(87) "Mosquitto\Client::setMaxInFlightMessages() expects parameter 1 to be long, object given"
string(%d) "Mosquitto\Client::setMaxInFlightMessages() expects parameter 1 to be %s, string given"
string(%d) "Mosquitto\Client::setMaxInFlightMessages() expects parameter 1 to be %s, object given"
4 changes: 2 additions & 2 deletions tests/Client/setMessageRetry.phpt
Expand Up @@ -37,5 +37,5 @@ object(Mosquitto\Client)#%d (0) {
}
object(Mosquitto\Client)#%d (0) {
}
string(80) "Mosquitto\Client::setMessageRetry() expects parameter 1 to be long, string given"
string(80) "Mosquitto\Client::setMessageRetry() expects parameter 1 to be long, object given"
string(%d) "Mosquitto\Client::setMessageRetry() expects parameter 1 to be %s, string given"
string(%d) "Mosquitto\Client::setMessageRetry() expects parameter 1 to be %s, object given"
4 changes: 2 additions & 2 deletions tests/Client/setReconnectDelay.phpt
Expand Up @@ -37,5 +37,5 @@ object(Mosquitto\Client)#%d (0) {
}
object(Mosquitto\Client)#%d (0) {
}
string(82) "Mosquitto\Client::setReconnectDelay() expects parameter 1 to be long, string given"
string(82) "Mosquitto\Client::setReconnectDelay() expects parameter 1 to be long, object given"
string(%d) "Mosquitto\Client::setReconnectDelay() expects parameter 1 to be %s, string given"
string(%d) "Mosquitto\Client::setReconnectDelay() expects parameter 1 to be %s, object given"
2 changes: 1 addition & 1 deletion tests/Client/setTlsOptions.phpt
Expand Up @@ -38,7 +38,7 @@ $client->setTlsOptions(Mosquitto\Client::SSL_VERIFY_PEER, 'tlsv1.2', 'DEFAULT');
?>
--EXPECTF--
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::setTlsOptions() expects at least 1 parameter, 0 given
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::setTlsOptions() expects parameter 1 to be long, object given
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::setTlsOptions() expects parameter 1 to be %s, object given
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::setTlsOptions() expects parameter 2 to be string, object given
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::setTlsOptions() expects parameter 3 to be string, object given

2 changes: 1 addition & 1 deletion tests/Client/subscribe.phpt
Expand Up @@ -73,7 +73,7 @@ Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::subscribe(
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::subscribe() expects exactly 2 parameters, 1 given
Caught Mosquitto\Exception with code 0 and message: The client is not currently connected.
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::subscribe() expects parameter 1 to be string, object given
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::subscribe() expects parameter 2 to be long, object given
Caught Mosquitto\Exception with code 0 and message: Mosquitto\Client::subscribe() expects parameter 2 to be %s, object given
array(3) {
[0]=>
int(%d)
Expand Down
6 changes: 2 additions & 4 deletions tests/Message/__construct.phpt
Expand Up @@ -77,8 +77,7 @@ object(Mosquitto\Message)#1 (5) {
bool(false)
}
Caught error 4096 (Object of class stdClass could not be converted to string) in %s on line 16
Caught error 8 (Object of class stdClass to string conversion) in %s on line 16
object(Mosquitto\Message)#1 (5) {
%Aobject(Mosquitto\Message)#1 (5) {
["mid"]=>
int(%d)
["topic"]=>
Expand All @@ -103,8 +102,7 @@ object(Mosquitto\Message)#1 (5) {
bool(false)
}
Caught error 4096 (Object of class stdClass could not be converted to string) in %s on line 22
Caught error 8 (Object of class stdClass to string conversion) in %s on line 22
object(Mosquitto\Message)#1 (5) {
%Aobject(Mosquitto\Message)#1 (5) {
["mid"]=>
int(%d)
["topic"]=>
Expand Down
5 changes: 5 additions & 0 deletions tests/setup.php
Expand Up @@ -2,6 +2,11 @@

define('CERTIFICATE_DIR', __DIR__ . '/certs/');

if (!class_exists("TypeError")) {
// Hack for PHP7 throwing type mismatches as TypeErrors rather than Mosquito\Exception
class TypeError extends Exception {}
}

$defaults = array(
'TEST_MQTT_HOST' => 'localhost',
'TEST_MQTT_PORT' => 1883,
Expand Down

0 comments on commit 1b6d14d

Please sign in to comment.