1. Trang chủ
  2. » Công Nghệ Thông Tin

PHP Object-Oriented Solutions phần 8 pptx

40 297 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 40
Dung lượng 1,3 MB

Nội dung

The RegexIterator is stored as $match, so a second foreach loop (the inner loop) iterates through $match, which contains only those titles with the string “PHP.” However, the outer loop goes through only one book at a time, so the code in the inner loop runs only if the current title matches the regular expression. Since the inner loop is nested inside the first, y ou can still access other properties associated with the current book through $ book . So, the appropriate <description> node is displayed by accessing $book->description. The inner loop comes to an end, and the outer loop moves onto the next book. If the regular expression doesn’t match, the inner loop never runs. One thing you need to be careful about is that even when there is no match, $match contains a RegexIterator object, so you can’t use the negative operator, empty(), or is_null() to detect a nonmatch. The for loop automatically takes care of nonmatches by skipping them. If you still find this difficult to grasp, load regex_iterator_02.php into a browser. It dis- plays onscreen the entry and exit points of both loops, together with the ordinary output, as shown in Figure 7-6. PHP OBJECT-ORIENTED SOLUTIONS 258 Figure 7-6. Displaying the entry and exit points of each loop shows how the RegexIterator filters the XML data. 10115ch07.qxd 7/10/08 1:00 PM Page 258 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Setting options for RegexIterator In addition to the two required arguments, the RegexIterator constructor accepts three optional arguments, namely: Mode: This controls how the regular expression is used by emulating the PCRE functions preg_match() and preg_match_all(). The default is to find a match for the regular expression. Flags: There is currently only one flag: RegexIterator::USE_KEY. This applies the regular expression to the key (or index) of each element, rather than the value. PREG_* flags: These are global PHP constants that control the way the regular expression is applied. They work the same way as with preg_match(), preg_match_all(), and preg_split(). Their use is rather specialized, so I don’t plan to cover them in this book. You can find a full list of the constants and their uses at http://docs.php.net/manual/en/pcre.constants.php. To set the mode and flags arguments, you need to use the class constants listed in Table 7-1. Table 7-1. RegexIterator class constants Constant Type Description MATCH Mode This returns true when there is a match for the regular expression. This is the default setting and doesn’t normally need to be used unless you set the other optional arguments. GET_MATCH Mode This returns the first match and captures any subexpressions. ALL_MATCHES Mode This emulates preg_match_all() and captures any subexpressions. SPLIT Mode This uses the regular expression to split the value and returns the resulting array. REPLACE Mode Currently not used. USE_KEY Flag This applies the regular expression to the key of each element , rather than the value. D isplaying messages identifying the current location in a loop is a good way of understanding the flow of a script, and it can help with debugging when things don’t turn out as expected. SUPERCHARGED LOOPING WITH SPL 259 7 10115ch07.qxd 7/10/08 1:00 PM Page 259 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com The best way to understand how these constants work is to see them in action. It also h elps if you have a good understanding of the PCRE functions, p reg_match() , p reg_match_all() , and p reg_split() . See the PHP Manual at h ttp://docs.php.net/ manual/en/book.pcre.php if you need to refresh your memory. Finding the first match and subexpressions Using the GET_MATCH mode constant emulates using preg_match() with the third argu- ment to capture any matches. It returns an array, the first element of which contains the entire string that matches the regular expression. Any subsequent array elements contain matching subexpressions. In the following example, the PCRE /(\w+?)e/ looks for as few as possible alphanumeric characters or the underscore followed by the letter “e.” The parentheses capture them as a subexpression (the code is in regex_iterator_03.php): $files = array('inventory.xml', 'createXML.php', 'modify_xml_03.php'); $iterator = new ArrayIterator($files); $regex = new RegexIterator($iterator, '/(\w+?)e/', ➥ RegexIterator::GET_MATCH); print_r(iterator_to_array($regex)); This produces the output shown in Figure 7-7. The third filename in the original array doesn’t contain the letter “e,” so results are produced only for the first two. Note that because GET_MATCH is a class constant, it needs to be preceded by the class name and the scope resolution operator ( ::). Figure 7-7. Using GET_MATCH produces an array of the first match and any subexpressions. The following examples use the function iterator_to_array(), which returns an array containing all the data in an iterator. This is useful for testing and debugging. PHP OBJECT-ORIENTED SOLUTIONS 260 10115ch07.qxd 7/10/08 1:00 PM Page 260 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Finding all matches T he A LL_MATCHES c onstant emulates p reg_match_all() . Changing the mode in the previ- ous example to ALL_MATCHES produces the output shown in Figure 7-8 (the code is in regex_iterator_04.php). Figure 7-8. The ALL_MATCHES mode produces an array of all matches and subexpressions. The interesting thing to note here is that ALL_MATCHES produces an empty array for the third filename, which doesn’t contain the letter “e.” In other words, it produces an array for each iteration, but the array is empty if there’s no match. SUPERCHARGED LOOPING WITH SPL 261 7 10115ch07.qxd 7/10/08 1:00 PM Page 261 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Splitting with a regular expression T he S PLIT m ode uses a regular expression to split the data in each element into an array. The regular expression /_|\./ in regex_iterator_05.php looks for an underscore or period and uses it as the separator on which to split the filenames, as shown in Figure 7-9. The code looks like this: $files = array('inventory.xml', 'createXML.php', 'modify_xml_03.php'); $iterator = new ArrayIterator($files); $regex = new RegexIterator($iterator, '/_|\./', RegexIterator::SPLIT); print_r(iterator_to_array($regex)); Figure 7-9. The SPLIT mode creates individual arrays of elements split on whatever matches the regular expression. The third filename contains two underscores and a period; both characters are used as the basis for the split. Applying the regular expression to the element keys By default, RegexIterator applies the PCRE to the value of each item in the iterator. However, setting the USE_KEY flag changes this behavior and applies the regular expression to the items’ keys instead. Because the USE_KEY flag must be passed to the constructor as the fourth argument, you must always set a value for the third argument when using it. The following code (in regex_iterator_06.php) uses the PCRE /^c/ to find strings that begin with the letter “ c.” Although MATCH is the default mode for RegexIterator, it needs to be set explicitly, so that USE_KEY can be passed to the constructor as the fourth argument. PHP OBJECT-ORIENTED SOLUTIONS 262 10115ch07.qxd 7/10/08 1:00 PM Page 262 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com $author = array('name' => 'David', 'city' => 'London', 'country' => 'United Kingdom'); $iterator = new ArrayIterator($author); $ regex = new RegexIterator($iterator, '/^c/', RegexIterator::MATCH, ➥ RegexIterator::USE_KEY); print_r(iterator_to_array($regex)); As you can see from Figure 7-10, the iterator selects the two keys that begin with “c.” Figure 7-10. The USE_KEY flag applies the regular expression to the key of each element instead of its value. Looping sequentially through more than one set of data The AppendIterator lets you append one or more iterators to another, and loop through them in one operation. Using it is very simple. You create an instance of the AppendIterator class and use its append() method to add each iterator in sequence. This can be very useful for processing data from different sources, as the following exercise shows. This exercise takes two XML documents with details of books published by friends of ED and its parent company, Apress. It combines them with AppendIterator and displays the titles in a single operation. It also shows how iterators can be chained to limit the number of items selected from each source. 1. Create a file called append_iterator.php in the ch7_exercises folder, and add the following code to load inventory.xml and more_books.xml as SimpleXMLIterator objects: $books = simplexml_load_file('inventory.xml', 'SimpleXMLIterator'); $moreBooks = simplexml_load_file('more_books.xml', ➥ 'SimpleXMLIterator'); The structure of more_books.xml is identical to inventory.xml (see Figure 6-2 in the previous chapter). It contains details of five books; inventory.xml contains six. Displaying book details from two sources SUPERCHARGED LOOPING WITH SPL 263 7 10115ch07.qxd 7/10/08 1:00 PM Page 263 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 2. C reate an instance of A ppendIterator , and then add each S impleXMLIterator i n turn by applying the append() method to the AppendIterator object like this: $books = simplexml_load_file('inventory.xml', 'SimpleXMLIterator'); $ moreBooks = simplexml_load_file('more_books.xml', ➥ 'SimpleXMLIterator'); $combined = new AppendIterator(); $combined->append($books); $combined->append($moreBooks); 3. You can now loop through the AppendIterator object to display the titles from both sources in a single operation. Add the following code immediately below the code in the previous step: echo '<ol>'; foreach ($combined as $book) { echo "<li>$book->title</li>"; } echo '</ol>'; 4. Save the page, and load it into a browser (or use append_iterator_01.php). You should see 11 titles displayed, as shown in Figure 7-11. Figure 7-11. Data from two separate sources is handled seamlessly by the AppendIterator class. 5. What happens, though, if each XML source contains a much larger number of items, and you want to show only the first few? The answer is simple: combine this operation with the LimitIterator class. Add the following lines highlighted in bold to select the first two items from each SimpleXMLIterator object: $moreBooks = simplexml_load_file('more_books.xml', ➥ 'SimpleXMLIterator'); $limit1 = new LimitIterator($books, 0, 2); $limit2 = new LimitIterator($moreBooks, 0, 2); $combined = new AppendIterator(); PHP OBJECT-ORIENTED SOLUTIONS 264 10115ch07.qxd 7/10/08 1:00 PM Page 264 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 6. Y ou now need to change the iterator objects passed to the a ppend() m ethod of the AppendIterator like this: $combined->append($limit1); $ combined->append( $ limit2 ) ; 7. Instead of $books and $moreBooks, which contain all the data, the $combined object now works with $limit1 and $limit2, which contain just the first two from each source. Prove it by saving the page, and loading it into a browser (or use append_iterator_02.php). You should see the same output as shown in Figure 7-12. Leave the file open, as I’ll come back to it in the next section. Figure 7-12. A combination of LimitIterator and AppendIterator makes it possible to select the first two from each source. Looking ahead with the CachingIterator Several of the books in inventory.xml and more_books.xml are written by multiple authors. In Chapter 6, I got around the problem of displaying their names by using a for loop with a series of conditional statements to insert commas between each name and an ampersand before the last one. The CachingIterator class makes it easy to do a similar thing in a foreach loop without the need for all the conditional statements. The CachingIterator provides a hasNext() method to look ahead to see if there’s another element to process after the current one. If there is, it returns true; otherwise, it returns false. You can use this to insert a comma after every name except the last one—not as ele- gant as adding the ampersand before the last name, but certainly a useful feature. So, let’s use the CachingIterator to fix the author ’s names. If you’re thinking you can use implode() or join() to insert a comma between array elements, don’t forget that it won’t work with SimpleXMLElement or SimpleXMLIterator objects. As you saw in the previous chapter , the <author> nodes of books with multiple authors are stored as an object, and not as an ordinary array. The implode() and join() functions won’t work on an object . SUPERCHARGED LOOPING WITH SPL 265 7 10115ch07.qxd 7/10/08 1:00 PM Page 265 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com This continues the exercise in the previous section, and uses the CachingIterator to dis- play the names of multiple authors with a comma between each one. If you don’t have the file from the previous exercise, use append_iterator_02.php in the ch7_exercises folder of the download files. 1. Amend the foreach loop like this: echo '<ol>'; foreach ($combined as $book) { echo "<li>$book->title"; $authors = new CachingIterator($book->author); echo '<ul><li>'; foreach ($authors as $name) { echo $name; if ($authors->hasNext()) { echo ', '; } } echo '</li></ul></li>'; } echo '</ol>'; Note that the closing </li> tag has been removed after $book->title, so that the authors’ names can be displayed as an indented bullet beneath the title. The third line in the foreach loop wraps $book->author in a CachingIterator and saves it as $authors. Then an inner loop iterates through $authors, using $name as the alias for each element, and displaying it with echo. The conditional statement calls the hasNext() method on the $authors object. If it returns true, it means there’s another name, so a comma followed by a space is inserted. If there is no other name, the condition equates to false, and the comma is omitted. 2. Save the page, and load it in a browser (or use caching_iterator_01.php). You should see the output in Figure 7-13. Inserting commas between authors’ names PHP OBJECT-ORIENTED SOLUTIONS 266 Figure 7-13. The CachingIterator makes it easy to add a comma between each author ’s name. 10115ch07.qxd 7/10/08 1:00 PM Page 266 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Not bad, but what if you don’t want to show all nine names for the third book on t he list? Yes, you’ve guessed it: a L imitIterator . 3. Amend the foreach loop like this: echo '<ol>'; foreach ($combined as $book) { echo "<li>$book->title"; $moreThan3 = false; if (count($book->author) > 3) { $limit3 = new LimitIterator($book->author, 0, 3); $authors = new CachingIterator($limit3); $moreThan3 = true; } else { $authors = new CachingIterator($book->author); } echo '<ul><li>'; foreach ($authors as $name) { echo $name; if ($authors->hasNext()) { echo ', '; } } if ($moreThan3) { echo ' et al'; } echo '</li></ul></li>'; } echo '</ol>'; It’s common to abbreviate long lists of authors’ names by showing just the first three and adding “et al.” or “and others” at the end of the list. The first new line highlighted in bold creates a flag called $moreThan3, which is initially set to false. The conditional statement passes $book->author to the count() function. If the result is more than 3, the code inside the braces is executed. This wraps $book->author in a LimitIterator that selects the first three names, and assigns it to $limit3. This, in turn, is wrapped in a CachingIterator and assigned to $authors. Finally, $moreThan3 is set to true. If the result is 3 or fewer, $book->author is wrapped directly in a CachingIterator and assigned to $authors. In either case, the iterator that displays the names is always called $authors. I tend to use the count() function out of habit, but SimpleXMLIterator and ArrayIterator objects also have a count() method. So, you could use $book->author->count() instead of count($book->author). Both do exactly the same thing. Use whichever you like. SUPERCHARGED LOOPING WITH SPL 267 7 10115ch07.qxd 7/10/08 1:00 PM Page 267 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... 286 10115ch07.qxd 7/10/ 08 1:00 PM Page 287 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 10115ch 08. qxd 7/14/ 08 1:51 PM Page 288 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 10115ch 08. qxd 7/14/ 08 1:54 PM Page 289 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 8 G E N E R AT I N G X M L F R O M A D ATA B A S E 10115ch 08. qxd... C:\htdocs\oopsolutions\ch7_exercises If I use that instead of the shorthand form, the full path is displayed like this: 272 10115ch07.qxd 7/10/ 08 1:00 PM Page 273 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com SUPERCHARGED LOOPING WITH SPL C:\htdocs\oopsolutions\ch7_exercises\anonymous_iterator_01 .php C:\htdocs\oopsolutions\ch7_exercises\anonymous_iterator_02 .php C:\htdocs\oopsolutions\ch7_exercises\append_iterator_01 .php. .. database queries If you need to get up to speed with MySQL and SQL, I suggest studying my earlier book PHP Solutions: Dynamic Web Design Made Easy (friends of ED, ISBN-13: 9 78- 1-59059-731-6) or Beginning PHP and MySQL: From Novice to Professional, Third Edition by W Jason Gilmore (Apress, ISBN-13: 9 78- 1-59059 -86 2-7) The class that converts the database result into an XML document forms the basis of a more... manual/en/function.sprintf .php) fseek() $pos, $whence Moves the file’s internal pointer It works the same way as the PHP function fseek() and uses the same constants (see http://docs .php. net/manual/en/ function.fseek .php) fstat() Outputs an array of statistics about the file (see http:// docs .php. net/manual/en/function.stat .php) ftell() Returns the current position of the file’s internal pointer ftruncate() $size Truncates... it should contain the following: This was written by an SplFileObject This was written using procedural code Each time you reload write_file_01 .php or write_file_02 .php, the relevant string will be added to newfile.txt 280 10115ch07.qxd 7/10/ 08 1:00 PM Page 281 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com SUPERCHARGED LOOPING WITH SPL You should have no difficulty using the... after the underscore (e.g., define Pos_MysqlImprovedConnection in MysqlImprovedConnection .php) Creating the database connection The MySQL Improved extension (http://docs .php. net/manual/en/book.mysqli .php) has both procedural functions and object-oriented methods, but since this book is dedicated to OOP, I’m using the object-oriented approach except where there is no alternative to a procedural function... such as FilterIterator, exist only as abstract classes, so you need to extend them before you can use them Also, all the classes in the Standard PHP Library are extensible, allowing you to create your own custom iterators 281 10115ch07.qxd 7/10/ 08 1:00 PM Page 282 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com P H P O B J E C T- O R I E N T E D S O L U T I O N S Understanding... The revised code (in filter_iterator_02 .php) looks like this: class PriceFilter extends FilterIterator { protected $_max; public function construct($iterator, $maxPrice) { parent:: construct($iterator); $this->_max = (float) $maxPrice; } public function accept() { return substr($this->current(), 1) _max; } } 284 10115ch07.qxd 7/10/ 08 1:00 PM Page 285 Simpo PDF Merge and Split Unregistered... already stored in the SplFileObject For example, the code in write_file_01 .php and write_file_02 .php opens a file called newfile.txt in the subfolder directory in append mode and writes a line of text If the newfile.txt doesn’t already exist, it’s automatically created Both files do the same thing, but write_file_01 .php uses the object-oriented approach with SplFileObject like this: $file = new SplFileObject('subfolder/newfile.txt',... $iterator nor the $limiter variable is necessary The code can be rewritten like this (it’s in anonymous_iterator_01 .php) : 2 68 10115ch07.qxd 7/10/ 08 1:00 PM Page 269 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com SUPERCHARGED LOOPING WITH SPL $numbers = array(5, 10, 8, 35, 50); foreach (new LimitIterator(new ArrayIterator($numbers), 0, 2) as $num) { echo $num ''; } Equally, . anonymous_iterator_01 .php) : PHP OBJECT-ORIENTED SOLUTIONS 2 68 10115ch07.qxd 7/10/ 08 1:00 PM Page 2 68 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com $numbers = array(5, 10, 8, 35, 50); foreach. http://www.simpopdf.com C:htdocsoopsolutionsch7_exercisesanonymous_iterator_01 .php C:htdocsoopsolutionsch7_exercisesanonymous_iterator_02 .php C:htdocsoopsolutionsch7_exercisesappend_iterator_01 .php . . . The. C:htdocsoopsolutionsch7_exercises. If I use that instead of the shorthand form, the full path is displayed like this: PHP OBJECT-ORIENTED SOLUTIONS 272 10115ch07.qxd 7/10/ 08 1:00 PM Page

Ngày đăng: 12/08/2014, 13:21

TỪ KHÓA LIÊN QUAN