@@ -95,6 +95,15 @@ class ExtendedPdo extends PDO implements ExtendedPdoInterface
95
95
*/
96
96
protected $ username ;
97
97
98
+ /**
99
+ *
100
+ * A specialized statement preparer.
101
+ *
102
+ * @var Rebuilder
103
+ *
104
+ */
105
+ protected $ rebuilder ;
106
+
98
107
/**
99
108
*
100
109
* This constructor is pseudo-polymorphic. You may pass a normal set of PDO
@@ -911,7 +920,8 @@ public function prepareWithValues($statement, array $values = array())
911
920
}
912
921
913
922
// rebuild the statement and values
914
- list ($ statement , $ values ) = $ this ->rebuild ($ statement , $ values );
923
+ $ rebuilder = new Rebuilder ($ this );
924
+ list ($ statement , $ values ) = $ rebuilder ->__invoke ($ statement , $ values );
915
925
916
926
// prepare the statement
917
927
$ sth = $ this ->prepare ($ statement );
@@ -924,210 +934,4 @@ public function prepareWithValues($statement, array $values = array())
924
934
// done
925
935
return $ sth ;
926
936
}
927
-
928
- /**
929
- *
930
- * Returns a new anonymous object to track bind values.
931
- *
932
- * @param array $values The values to bind and/or replace into a statement.
933
- *
934
- * @return object
935
- *
936
- */
937
- protected function newBindTracker ($ values )
938
- {
939
- // anonymous object to track preparation info
940
- return (object ) array (
941
- // how many numbered placeholders in the original statement
942
- 'num ' => 0 ,
943
- // how many numbered placeholders to actually be bound; this may
944
- // differ from 'num' in that some numbered placeholders may get
945
- // replaced with quoted CSV strings
946
- 'count ' => 0 ,
947
- // initial values to be bound
948
- 'values ' => $ values ,
949
- // named and numbered placeholders to bind at the end
950
- 'final_values ' => array (),
951
- );
952
- }
953
-
954
- /**
955
- *
956
- * Rebuilds a statement with array values replaced into placeholders.
957
- *
958
- * @param string $statement The statement to rebuild.
959
- *
960
- * @param array $values The values to bind and/or replace into a statement.
961
- *
962
- * @return array An array where element 0 is the rebuilt statement and
963
- * element 1 is the rebuilt array of values.
964
- *
965
- */
966
- protected function rebuild ($ statement , $ values )
967
- {
968
- $ bind = $ this ->newBindTracker ($ values );
969
- $ statement = $ this ->rebuildStatement ($ statement , $ bind );
970
- return array ($ statement , $ bind ->final_values );
971
- }
972
-
973
- /**
974
- *
975
- * Given a statement, rebuilds it with array values embedded.
976
- *
977
- * @param string $statement The SQL statement.
978
- *
979
- * @param object $bind The bind-values tracker.
980
- *
981
- * @return string The rebuilt statement.
982
- *
983
- */
984
- protected function rebuildStatement ($ statement , $ bind )
985
- {
986
- // find all parts not inside quotes or backslashed-quotes
987
- $ apos = "' " ;
988
- $ quot = '" ' ;
989
- $ parts = preg_split (
990
- "/(( $ apos+| $ quot+| \\$ apos+| \\$ quot+).*?) \\2/m " ,
991
- $ statement ,
992
- -1 ,
993
- PREG_SPLIT_DELIM_CAPTURE
994
- );
995
- return $ this ->rebuildParts ($ parts , $ bind );
996
- }
997
-
998
- /**
999
- *
1000
- * Given an array of statement parts, rebuilds each part.
1001
- *
1002
- * @param array $parts The statement parts.
1003
- *
1004
- * @param object $bind The bind-values tracker.
1005
- *
1006
- * @return string The rebuilt statement.
1007
- *
1008
- */
1009
- protected function rebuildParts ($ parts , $ bind )
1010
- {
1011
- // loop through the non-quoted parts (0, 3, 6, 9, etc.)
1012
- $ k = count ($ parts );
1013
- for ($ i = 0 ; $ i <= $ k ; $ i += 3 ) {
1014
- $ parts [$ i ] = $ this ->rebuildPart ($ parts [$ i ], $ bind );
1015
- }
1016
- return implode ('' , $ parts );
1017
- }
1018
-
1019
- /**
1020
- *
1021
- * Rebuilds a single statement part.
1022
- *
1023
- * @param string $part The statement part.
1024
- *
1025
- * @param object $bind The bind-values tracker.
1026
- *
1027
- * @return string The rebuilt statement.
1028
- *
1029
- */
1030
- protected function rebuildPart ($ part , $ bind )
1031
- {
1032
- // split into subparts by ":name" and "?"
1033
- $ subs = preg_split (
1034
- "/(:[a-zA-Z_][a-zA-Z0-9_]*)|(\?)/m " ,
1035
- $ part ,
1036
- -1 ,
1037
- PREG_SPLIT_DELIM_CAPTURE
1038
- );
1039
-
1040
- // check subparts to convert bound arrays to quoted CSV strings
1041
- $ subs = $ this ->prepareValuePlaceholders ($ subs , $ bind );
1042
-
1043
- // reassemble
1044
- return implode ('' , $ subs );
1045
- }
1046
-
1047
- /**
1048
- *
1049
- * Prepares the sub-parts of a query with placeholders.
1050
- *
1051
- * @param array $subs The query subparts.
1052
- *
1053
- * @param object $bind The preparation info object.
1054
- *
1055
- * @return array The prepared subparts.
1056
- *
1057
- */
1058
- protected function prepareValuePlaceholders (array $ subs , $ bind )
1059
- {
1060
- foreach ($ subs as $ i => $ sub ) {
1061
- $ char = substr ($ sub , 0 , 1 );
1062
- if ($ char == '? ' ) {
1063
- $ subs [$ i ] = $ this ->prepareNumberedPlaceholder ($ sub , $ bind );
1064
- }
1065
-
1066
- if ($ char == ': ' ) {
1067
- $ subs [$ i ] = $ this ->prepareNamedPlaceholder ($ sub , $ bind );
1068
- }
1069
- }
1070
-
1071
- return $ subs ;
1072
- }
1073
-
1074
- /**
1075
- *
1076
- * Bind or quote a numbered placeholder in a query subpart.
1077
- *
1078
- * @param string $sub The query subpart.
1079
- *
1080
- * @param object $bind The preparation info object.
1081
- *
1082
- * @return string The prepared query subpart.
1083
- *
1084
- */
1085
- protected function prepareNumberedPlaceholder ($ sub , $ bind )
1086
- {
1087
- // what numbered placeholder is this in the original statement?
1088
- $ bind ->num ++;
1089
-
1090
- // is the corresponding data element an array?
1091
- $ bind_array = isset ($ bind ->values [$ bind ->num ])
1092
- && is_array ($ bind ->values [$ bind ->num ]);
1093
- if ($ bind_array ) {
1094
- // PDO won't bind an array; quote and replace directly
1095
- $ sub = $ this ->quote ($ bind ->values [$ bind ->num ]);
1096
- } else {
1097
- // increase the count of numbered placeholders to be bound
1098
- $ bind ->count ++;
1099
- $ bind ->final_values [$ bind ->count ] = $ bind ->values [$ bind ->num ];
1100
- }
1101
-
1102
- return $ sub ;
1103
- }
1104
-
1105
- /**
1106
- *
1107
- * Bind or quote a named placeholder in a query subpart.
1108
- *
1109
- * @param string $sub The query subpart.
1110
- *
1111
- * @param object $bind The preparation info object.
1112
- *
1113
- * @return string The prepared query subpart.
1114
- *
1115
- */
1116
- protected function prepareNamedPlaceholder ($ sub , $ bind )
1117
- {
1118
- $ name = substr ($ sub , 1 );
1119
-
1120
- // is the corresponding data element an array?
1121
- $ bind_array = isset ($ bind ->values [$ name ])
1122
- && is_array ($ bind ->values [$ name ]);
1123
- if ($ bind_array ) {
1124
- // PDO won't bind an array; quote and replace directly
1125
- $ sub = $ this ->quote ($ bind ->values [$ name ]);
1126
- } else {
1127
- // not an array, retain the placeholder for later
1128
- $ bind ->final_values [$ name ] = $ bind ->values [$ name ];
1129
- }
1130
-
1131
- return $ sub ;
1132
- }
1133
937
}
0 commit comments