From 5561a107a05125b1c7308a18bbf639efff022526 Mon Sep 17 00:00:00 2001 From: sbuberl Date: Sat, 16 Mar 2019 22:45:25 -0400 Subject: [PATCH] #10 Fixed bind_param to take references too --- src/Statement.php | 83 ++++++++++++++++++++++++----------------- tests/StatementTest.php | 50 ++++++++++++++++++++----- 2 files changed, 88 insertions(+), 45 deletions(-) diff --git a/src/Statement.php b/src/Statement.php index 9cc577e..d133ff7 100644 --- a/src/Statement.php +++ b/src/Statement.php @@ -11,7 +11,9 @@ class Statement private $params; private $result; private $metadata; - private $bound; + private $types; + private $boundParams; + private $boundResults; private $stored; private $error; @@ -32,7 +34,7 @@ private function set_error($error) return false; } - public function bind_param($types, ...$params) + public function bind_param($types, &...$params) { $length = strlen($types); if($this->query === null) { @@ -41,27 +43,8 @@ public function bind_param($types, ...$params) return $this->set_error("bind_param's number of types in the string doesn't match number of parameters passed in"); } - $param = current($params); - - for($i = 0; $i < $length; ++$i, $param = next($params)) { - $type = $types[$i]; - if($param == null) { - $this->params[] = 'NULL'; - } else { - switch($type) { - case 'i': - $this->params[] = (int) $param; - break; - case 'd': - $this->params[] = (float) $param; - break; - case 's': - case 'o': - $this->params[] = "'". addslashes((string) $param) . "'"; - break; - } - } - } + $this->boundParams = $params; + $this->types = $types; return true; } @@ -74,7 +57,7 @@ public function bind_result(&...$variables) return $this->set_error("No result set found for bind_result"); } - $this->bound = $variables; + $this->boundResults = $variables; return true; } @@ -84,14 +67,42 @@ public function execute() return $this->set_error("Unable to perform an execute without a prepare"); } - $that = $this; - $count = 0; - $newQuery = preg_replace_callback( - "/\?(?=[^']*(?:'[^']*'[^']*)*$)/", - function($match) use ($that, &$count) { return $that->params[$count++]; }, - $this->query - ); - $result = $this->environment->query($newQuery); + if($this->boundParams !== null) { + $length = strlen($this->types); + $param = current($this->boundParams); + + $params = []; + for($i = 0; $i < $length; ++$i, $param = next($this->boundParams)) { + $type = $this->types[$i]; + if($param == null) { + $params[] = 'NULL'; + } else { + switch($type) { + case 'i': + $params[] = (int) $param; + break; + case 'd': + $params[] = (float) $param; + break; + case 's': + case 'o': + $params[] = "'". addslashes((string) $param) . "'"; + break; + } + } + } + $parameters = $params; + $count = 0; + $realQuery = preg_replace_callback( + "/\?(?=[^']*(?:'[^']*'[^']*)*$)/", + function($match) use ($parameters, &$count) { return $parameters[$count++]; }, + $this->query + ); + } else { + $realQuery = $this->query; + } + + $result = $this->environment->query($realQuery); if($result instanceof ResultSet) { $this->result = $result; $this->metadata = $result->createMetadata(); @@ -107,7 +118,7 @@ public function fetch() { if($this->query === null) { return $this->set_error("Unable to perform a fetch without a prepare"); - } elseif($this->bound === null) { + } elseif($this->boundResults === null) { return $this->set_error("Unable to perform a fetch without a bind_result"); } @@ -115,7 +126,7 @@ public function fetch() if($result !== null) { $i = 0; foreach ($result as $value) { - $this->bound[$i++] = $value; + $this->boundResults[$i++] = $value; } return true; } @@ -128,7 +139,9 @@ public function prepare($query) $this->params = []; $this->result = null; $this->metadata = null; - $this->bound = null; + $this->types = null; + $this->boundParams = null; + $this->boundResults = null; $this->stored = false; return true; } diff --git a/tests/StatementTest.php b/tests/StatementTest.php index a2625da..94e513c 100644 --- a/tests/StatementTest.php +++ b/tests/StatementTest.php @@ -52,7 +52,10 @@ public function testPrepare() public function testBindParamNoPrepare() { $statement = new Statement($this->fsql); - $passed = $statement->bind_param('isd', '5', 'king', 99999); + $id = 5; + $lastName = 'king'; + $zip = 99999; + $passed = $statement->bind_param('isd', $id, $lastName, $zip); $this->assertTrue($passed === false); $this->assertEquals($statement->error(), "Unable to perform a bind_param without a prepare"); } @@ -61,7 +64,9 @@ public function testBindParamTypeParamMismatch() { $statement = new Statement($this->fsql); $statement->prepare("SELECT firstName, lastName, city FROM customers WHERE personId = ? OR lastName = ? OR zip = ?"); - $passed = $statement->bind_param('isd', '5', 'king'); + $id = 5; + $lastName = 'king'; + $passed = $statement->bind_param('isd', $id, $lastName); $this->assertTrue($passed === false); $this->assertEquals($statement->error(), "bind_param's number of types in the string doesn't match number of parameters passed in"); } @@ -70,7 +75,10 @@ public function testBindParam() { $statement = new Statement($this->fsql); $statement->prepare("SELECT firstName, lastName, city FROM customers WHERE personId = ? OR lastName = ? OR zip = ?"); - $passed = $statement->bind_param('isd', '5', 'king', 99999); + $id = 5; + $lastName = 'king'; + $zip = 99999; + $passed = $statement->bind_param('isd', $id, $lastName, $zip); $this->assertTrue($passed === true); } @@ -132,7 +140,13 @@ public function testExecuteParams() $statement = new Statement($this->fsql); $statement->prepare("SELECT firstName, lastName, city FROM customers WHERE personId = ? OR lastName = ? OR zip = ?"); - $statement->bind_param('isd', '5', 'king', 99999); + $id = 5; + $lastName = 'king'; + $zip = 99999; + $statement->bind_param('isd', $id, $lastName, $zip); + $passed = $statement->execute(); + $this->assertTrue($passed === true); + } $passed = $statement->execute(); $this->assertTrue($passed === true); } @@ -145,7 +159,7 @@ public function testBindResultNoPrepare() $this->assertEquals($statement->error(), "Unable to perform a bind_result without a prepare"); } - public function testBindParamNoResult() + public function testBindResultNoResult() { $table = CachedTable::create($this->fsql->current_schema(), 'customers', self::$columns); $cursor = $table->getWriteCursor(); @@ -156,7 +170,10 @@ public function testBindParamNoResult() $statement = new Statement($this->fsql); $statement->prepare("SELECT firstName, lastName, city FROM customers WHERE personId = ? OR lastName = ? OR zip = ?"); - $statement->bind_param('isd', '5', 'king', null); + $id = 5; + $last = 'king'; + $zip = 99999; + $statement->bind_param('isd', $id, $last, $zip); $passed = $statement->bind_result($firstName, $lastName, $city); $this->assertTrue($passed === false); $this->assertEquals($statement->error(), "No result set found for bind_result"); @@ -173,7 +190,10 @@ public function testBindResult() $statement = new Statement($this->fsql); $statement->prepare("SELECT firstName, lastName, city FROM customers WHERE personId = ? OR lastName = ? OR zip = ?"); - $statement->bind_param('isd', '5', 'king', null); + $id = 5; + $last = 'king'; + $zip = 99999; + $statement->bind_param('isd', $id, $last, $zip); $statement->execute(); $passed = $statement->bind_result($firstName, $lastName, $city); $this->assertTrue($passed === true); @@ -198,7 +218,10 @@ public function testFetchNoBindResult() $statement = new Statement($this->fsql); $statement->prepare("SELECT firstName, lastName, city FROM customers WHERE personId = ? OR lastName = ? OR zip = ?"); - $statement->bind_param('isd', '5', 'king', null); + $id = 5; + $last = 'king'; + $zip = 99999; + $statement->bind_param('isd', $id, $last, $zip); $statement->execute(); $passed = $statement->fetch(); $this->assertTrue($passed === false); @@ -216,13 +239,17 @@ public function testFetch() $statement = new Statement($this->fsql); $statement->prepare("SELECT firstName, lastName, city FROM customers WHERE personId = ? OR lastName = ? OR zip = ?"); - $statement->bind_param('isd', '5', 'king', null); + $id = 5; + $last = 'king'; + $zip = 99999; + $statement->bind_param('isd', $id, $last, $zip); $statement->execute(); $statement->bind_result($firstName, $lastName, $city); $i = 0; $expected = [ ['stephen', 'king', 'derry'], ['bart', 'simpson', 'springfield'], + ['douglas', 'adams', 'london'], [null, 'king', 'tokyo'], ]; while($statement->fetch()) { @@ -252,7 +279,10 @@ public function testStoreResult() $statement = new Statement($this->fsql); $statement->prepare("SELECT firstName, lastName, city FROM customers WHERE personId = ? OR lastName = ? OR zip = ?"); - $statement->bind_param('isd', '5', 'king', null); + $id = 5; + $last = 'king'; + $zip = 99999; + $statement->bind_param('isd', $id, $last, $zip); $statement->execute(); $passed = $statement->store_result(); $this->assertTrue($passed === true);