flounder Posted October 1, 2011 Share Posted October 1, 2011 Hello all, I have a 14 column csv that I load into an array, retrieving only the required fields, load the array into columns and perform a sort: foreach ($array as $key => $row) { $firstname[$key] = $row["firstn"]; $lastname[$key] = $row["lastn"]; $address1[$key] = $row["addr1"]; $address2[$key] = $row["addr2"]; $address3[$key] = $row["addr3"]; $city[$key] = $row["cit"]; $stateprov[$key] = $row["state"]; $country[$key] = $row["cntry"]; $membernumber[$key] = $row["num"];} array_multisort($membernumber,$lastname,$firstname,$address1,$address2,$address3,$city,$stateprov,$country,$array); When I pass say the first three letters of a last name ($find = "smi"), all records matching the search criteria are returned: foreach ($array as $key => $row) { if (strncasecmp($find, $lastname[$key], strlen($find)) == 0) { echo "<tr><td>" . $firstname[$key] . "</td>"; echo "<td>" . $lastname[$key] . "</td>"; echo "<td>" . $address1[$key] . "</td>"; echo "<td>" . $address2[$key] . "</td>"; echo "<td>" . $address3[$key] . "</td>"; echo "<td>" . $city[$key] . "</td>"; echo "<td>" . $stateprov[$key] . "</td>"; echo "<td>" . $country[$key] . "</td>"; echo "<td>" . $membernumber[$key] . "</td></tr>" . chr(13); }}} So far so good. However, I'd like to put the search part into a function so I can call it a number of times without having to reload the entire csv: function FindMember() { foreach ($array as $key => $row) { if (strncasecmp($find, $membernumber[$key], strlen($find)) == 0) { echo "<tr><td>" . $firstname[$key] . "</td>"; echo "<td>" . $lastname[$key] . "</td>"; echo "<td>" . $address1[$key] . "</td>"; echo "<td>" . $address2[$key] . "</td>"; echo "<td>" . $address3[$key] . "</td>"; echo "<td>" . $city[$key] . "</td>"; echo "<td>" . $stateprov[$key] . "</td>"; echo "<td>" . $country[$key] . "</td>"; echo "<td align='right'>" . $membernumber[$key] . "</td></tr>" . chr(13); }}}} The search criteria would come from a second txt file with every line containing 2 numbers, separated by a comma: foreach ($lines as $member => $numbers) { $exploded = explode(",", $numbers); $find = $exploded[1]; FindMember(); here $exploded[1] corresponds to $membernumber[$key], so this is where I would call the function, but this is where I run into trouble, nothing gets returned. Does this have something to do with the scope of variables inside a user-defined function? I'd appreciate it if someone could point me in the right direction. TIA Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/ Share on other sites More sharing options...
mikesta707 Posted October 1, 2011 Share Posted October 1, 2011 Yes, unless you use the global keyword, no variables with a script-wide scope will be available in functions. Using global is generally frowned upon however, as it makes the function you created dependent on outside information, which greatly reduces its portability and re-usability. Functions should only be dependent on the information you pass into its argument list. Is there a reason you don't just pass the relevant arrays into the function via the argument list? Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/#findComment-1274721 Share on other sites More sharing options...
flounder Posted October 1, 2011 Author Share Posted October 1, 2011 Hi mikesta707 thanks for the quick response. I'm quite new to php so I'm sorry I have to ask: pass the relevant arrays into the function via the argument list How do I do that? Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/#findComment-1274724 Share on other sites More sharing options...
mikesta707 Posted October 1, 2011 Share Posted October 1, 2011 When creating a function in PHP (and in pretty much any programming language) You have to option of specifying parameters in the argument list (The stuff between the parentheses) that allows you to pass information to the function that is available at the time of the function call. So for example function foo($arg1, $arg2){//the ($arg1, $arg2) part is the argument list echo $arg1 . " is friends with " . $arg2; } //some random amount of code or whatever //... foo("John", "Nick");//output: John is friends with Nick foo("Mike", "Kyle");//output: Mike is friends with Kyle //the names John, Nick, Mike, and Kyle aren't available when we define the function (we don't know the names yet!) //but will be available when you run the script later on, and decide who you say is friends with who //obviously the names are arbitrarily picked in this code, and could be hard coded in the function //but the example illustrates my point well enough I think In the case of your code, the arguments that you may want to pass would be the arrays that you are iterating through (namely $array and $membernumber) Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/#findComment-1274727 Share on other sites More sharing options...
flounder Posted October 1, 2011 Author Share Posted October 1, 2011 So what am I missing here? I changed the function to: function FindNumber($arr, $find) { foreach ($arr as $key => $row) { if (strncasecmp($find, $membernumber[$key], strlen($find)) == 0) Pass it the arguments: FindNumber($array, $exploded[1]); Stll nothing gets returned.... Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/#findComment-1274734 Share on other sites More sharing options...
KevinM1 Posted October 1, 2011 Share Posted October 1, 2011 Do you actually return anything from your function? Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/#findComment-1274748 Share on other sites More sharing options...
flounder Posted October 1, 2011 Author Share Posted October 1, 2011 Hi Nightslyr, that was a helpful hint: I changed my function to: function FindNumber($arr, $find) { foreach ($arr as $key => $row) { if (strncasecmp($find, $membernumber[$key], strlen($find)) == 0) { return ($lastname[$key]}}} The call to the function: foreach ($lines as $donor => $numbers) { $exploded = explode(",", $numbers); FindNumber($array, $exploded[1]); echo $lastname[$key];} Now in each case the very last record gets returned though. I thought the return statement would halt execution of the function and return the current record... Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/#findComment-1274755 Share on other sites More sharing options...
xyph Posted October 1, 2011 Share Posted October 1, 2011 If $membernumer is unique, then sorting it like this array_multisort($membernumber,$lastname,$firstname,$address1,$address2,$address3,$city,$stateprov,$country,$array); is redundant. Instead, use array_multisort($membernumber,$array); Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/#findComment-1274762 Share on other sites More sharing options...
flounder Posted October 1, 2011 Author Share Posted October 1, 2011 Thanks xyph, I deleted the redundant $'s from the array_mutisort statement as $membernumber is indeed unique, but again every time the last record is returned, not the one where $exploded[1] = $membernumber[$key]. Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/#findComment-1274767 Share on other sites More sharing options...
xyph Posted October 1, 2011 Share Posted October 1, 2011 <?php $csv = array( array( 'uid'=>'1', 'fname'=>'John', 'lname'=>'Smith', 'city'=>'Toronto' ), array( 'uid'=>'2', 'fname'=>'Jim', 'lname'=>'Smith', 'city'=>'Calgary' ), array( 'uid'=>'3', 'fname'=>'Steve', 'lname'=>'Smitty', 'city'=>'Toronto' ), array( 'uid'=>'4', 'fname'=>'Bob', 'lname'=>'Johnson', 'city'=>'Toronto' ), array( 'uid'=>'5', 'fname'=>'Tom', 'lname'=>'Smithers', 'city'=>'Vancouver' ), ); $search = new arraySearch( $csv ); $result = $search->findMultiple( 'lname','smi', 'city','tor' ); print_r( $result ); class arraySearch { private $data; public function __construct( $array ) { $this->data = $array; } public function findByStart( $col, $val, $data = FALSE ) { $r = array(); $l = strlen( $val ); if( $data == FALSE ) $data = $this->data; foreach( $data as $line ) { if( !isset($line[$col]) ) continue; // Column doesn exist if( strncasecmp($line[$col], $val, $l) === 0 ) $r[] = $line; } return $r; } public function findMultiple() { $args = func_get_args(); $num = func_num_args(); $data = $this->data; for( $i = 0; $i < $num; $i+=2 ) { $data = $this->findByStart($args[$i], $args[$i+1], $data); } return $data; } } ?> If you get lost in the OOP, let me know and I'll type up a procedural version. Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/#findComment-1274774 Share on other sites More sharing options...
flounder Posted October 1, 2011 Author Share Posted October 1, 2011 Yo xyph, thank you very much for taking the time to post what you did. As I stated earlier, I'm quite new to php. However, I've been programming since 1985 starting with a Radio Shack TRS80 with a cassette deck for a storage device. As far as I can tell, my problem currently is the array pointer; I have no idea how to relate your post with my situation, Thanks again, Chris Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/#findComment-1274779 Share on other sites More sharing options...
xyph Posted October 1, 2011 Share Posted October 1, 2011 I don't really follow your logic in the code provided above. Rather than try to follow your logic through array pointers, I have provided a script that does what you want in a differnt, possibly easier to understand way. I'll rewrite it in procedural form with comments and hopefully you'll follow. Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/#findComment-1274783 Share on other sites More sharing options...
xyph Posted October 1, 2011 Share Posted October 1, 2011 <?php // This is sort of how you've arranged your data, I'm assuming. $csv = array( array( 'uid'=>'5', 'fname'=>'John', 'lname'=>'Smith', 'city'=>'Toronto' ), array( 'uid'=>'2', 'fname'=>'Jim', 'lname'=>'Smith', 'city'=>'Calgary' ), array( 'uid'=>'1', 'fname'=>'Steve', 'lname'=>'Smitty', 'city'=>'Toronto' ), array( 'uid'=>'4', 'fname'=>'Bob', 'lname'=>'Johnson', 'city'=>'Toronto' ), array( 'uid'=>'4', 'fname'=>'Tom', 'lname'=>'Smithers', 'city'=>'Vancouver' ), ); // Quickly sort by uid usort( $csv, 'usort_UID' ); // $csv is now sorted by [x]['uid'] // Get an array of values of 'lname' that start with 'smi' $csv_smi = findByStart( $csv, 'lname', 'smi'); // Preview this array echo '<pre>'; print_r( $csv_smi ); echo '</pre>'; // Get an array of values of 'city' that start with 'tor' from our previous // results of 'lname' that starts with 'smi' $csv_tor = findByStart( $csv_smi, 'city', 'tor' ); // Notice how I use our previously returned results ($csv_smi) to only search // through those results // Here's where the work's done! // Function I use to quickly sort by a sub-key in an array while using usort() // Check it out in the manual for more details function usort_UID( $a, $b ) { return $a['uid'] > $b['uid']; } /** * * Used to return only results from an array that match the start of a given * subkey's value. Case-insensitive. * @param $data The array to search. * @param $col The column of the subarrays to search. * @param $val The starting value to match. */ function findByStart( $data, $col, $val ) { // This will hold our result data $r = array(); // This gets the length of the string to check, needed for strncasecmp() $l = strlen( $val ); // Loop through each entry in the array foreach( $data as $row ) { // Check if the column even exists for this row if( !isset($row[$col]) ) continue; // Skips the rest of this iteration // Check if the values are equal up to the given length // (strncasecmp returns 0 if they are) if( strncasecmp($row[$col], $val, $l) === 0 ) // Add a new array into our result data containing the matching data $r[] = $row; } // Return the result data return $r; } ?> Hope that helps. Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/#findComment-1274792 Share on other sites More sharing options...
flounder Posted October 1, 2011 Author Share Posted October 1, 2011 xyph, I sent you a PM, it's not showing up in my Sent Items, did you get it? Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/#findComment-1274794 Share on other sites More sharing options...
xyph Posted October 1, 2011 Share Posted October 1, 2011 Indeed. Email sent. Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/#findComment-1274795 Share on other sites More sharing options...
flounder Posted October 1, 2011 Author Share Posted October 1, 2011 Maybe I'm getting too old for this, I did not receive your response.... Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/#findComment-1274801 Share on other sites More sharing options...
xyph Posted October 1, 2011 Share Posted October 1, 2011 No, that was my bad. Recently switched ISPs, and my last ISP forced me to use their SMTP server for all outgoing emails. Had it left at that. Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/#findComment-1274806 Share on other sites More sharing options...
ignace Posted October 2, 2011 Share Posted October 2, 2011 I see xyph already helped you, I'll add the below code if anyone ever comes across this topic. I had a play with it yesterday and tried to mimic SQL like functionality in PHP for CSV files. Please use SQL for any large CSV file. class CSVFileObject { private $_file; private $_skipFirst; public function __construct($csvFile, $delimiter = ',', $enclosure = '"', $escape = '\\', $skipFirst = false) { $this->_file = new SplFileObject($csvFile); $this->_file->setFlags(SplFileObject::READ_CSV); $this->_file->setCsvControl($delimiter, $enclosure, $escape); $this->_skipFirst = $skipFirst; } public function rewind() { $this->_file->rewind(); } public function readLine($line = null) { if ($line !== null) { $this->_file->seek($line); } if (!$this->_file->valid()) { return false; } if ($this->_file->key() === 0 && $this->_skipFirst) { $this->_file->next(); if (!$this->_file->valid()) { return false; } } $line = $this->_file->current(); $this->_file->next(); if (!is_array($line)) { return false; } return $line; } } interface Matcher { public function match($o); } class CSVComplexSearch { private $_csv; public function __construct(CSVFileObject $csv) { $this->_csv = $csv; } public function findWhereMatches(Matcher $matcher) { $result = new ArrayObject; while (($line = $this->_csv->readLine()) !== false) { if ($matcher->match($line)) { $result->append($line); } } return $result; } } class MyMatcher implements Matcher { private $_line; public function match($o) { $this->_line = $o; return ( $this->_whereFirstNameIs('foo') && $this->_whereLastNameIs('bar') ); } private function _whereFirstNameIs($str) { return $this->_line[0] === $str; } private function _whereLastNameIs($str) { return $this->_line[1] === $str; } } You use it like this: $search = new CSVComplexSearch(new CSVFileObject('users.csv')); var_dump($search->findWhereMatches(new MyMatcher)); Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/#findComment-1274868 Share on other sites More sharing options...
flounder Posted October 4, 2011 Author Share Posted October 4, 2011 So it took me a couple of days to figure this out (I'm old and I'm slow). This is what I was looking for: The function function FindNumber($arr, $find) { foreach ($arr as $key => $value) { foreach ($value as $num => $val) { if ($value["num"] == $find) { $result = $value; return $result;}}}} The call passing the parameters: foreach ($lines as $donor => $numbers) { $exploded = explode(",", $numbers); $name = FindNumber($array, $exploded[1]); foreach ($name as $num => $val) { echo $val;}} Works like a charm! Quote Link to comment https://forums.phpfreaks.com/topic/248232-scope-of-variables-inside-a-user-defined-function/#findComment-1275691 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.