| Conditions | 88 | 
| Paths | > 20000 | 
| Total Lines | 372 | 
| Code Lines | 202 | 
| Lines | 56 | 
| Ratio | 15.05 % | 
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
| 1 | <?php  | 
            ||
| 494 | public static function findNodes(DOMDocument $dom, array $options, $isHtml = true)  | 
            ||
| 495 |     { | 
            ||
| 496 | $valid = array(  | 
            ||
| 497 | 'id', 'class', 'tag', 'content', 'attributes', 'parent',  | 
            ||
| 498 | 'child', 'ancestor', 'descendant', 'children', 'adjacent-sibling'  | 
            ||
| 499 | );  | 
            ||
| 500 | |||
| 501 | $filtered = array();  | 
            ||
| 502 | $options = self::assertValidKeys($options, $valid);  | 
            ||
| 503 | |||
| 504 | // find the element by id  | 
            ||
| 505 |         if ($options['id']) { | 
            ||
| 506 | $options['attributes']['id'] = $options['id'];  | 
            ||
| 507 | }  | 
            ||
| 508 | |||
| 509 |         if ($options['class']) { | 
            ||
| 510 | $options['attributes']['class'] = $options['class'];  | 
            ||
| 511 | }  | 
            ||
| 512 | |||
| 513 | $nodes = array();  | 
            ||
| 514 | |||
| 515 | // find the element by a tag type  | 
            ||
| 516 |         if ($options['tag']) { | 
            ||
| 517 |             if ($isHtml) { | 
            ||
| 518 | $elements = self::getElementsByCaseInsensitiveTagName(  | 
            ||
| 519 | $dom,  | 
            ||
| 520 | $options['tag']  | 
            ||
| 521 | );  | 
            ||
| 522 |             } else { | 
            ||
| 523 | $elements = $dom->getElementsByTagName($options['tag']);  | 
            ||
| 524 | }  | 
            ||
| 525 | |||
| 526 |             foreach ($elements as $element) { | 
            ||
| 527 | $nodes[] = $element;  | 
            ||
| 528 | }  | 
            ||
| 529 | |||
| 530 |             if (empty($nodes)) { | 
            ||
| 531 | return false;  | 
            ||
| 532 | }  | 
            ||
| 533 | } // no tag selected, get them all  | 
            ||
| 534 |         else { | 
            ||
| 535 | $tags = array(  | 
            ||
| 536 | 'a', 'abbr', 'acronym', 'address', 'area', 'b', 'base', 'bdo',  | 
            ||
| 537 | 'big', 'blockquote', 'body', 'br', 'button', 'caption', 'cite',  | 
            ||
| 538 | 'code', 'col', 'colgroup', 'dd', 'del', 'div', 'dfn', 'dl',  | 
            ||
| 539 | 'dt', 'em', 'fieldset', 'form', 'frame', 'frameset', 'h1', 'h2',  | 
            ||
| 540 | 'h3', 'h4', 'h5', 'h6', 'head', 'hr', 'html', 'i', 'iframe',  | 
            ||
| 541 | 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'link',  | 
            ||
| 542 | 'map', 'meta', 'noframes', 'noscript', 'object', 'ol', 'optgroup',  | 
            ||
| 543 | 'option', 'p', 'param', 'pre', 'q', 'samp', 'script', 'select',  | 
            ||
| 544 | 'small', 'span', 'strong', 'style', 'sub', 'sup', 'table',  | 
            ||
| 545 | 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'title',  | 
            ||
| 546 | 'tr', 'tt', 'ul', 'var',  | 
            ||
| 547 | // HTML5  | 
            ||
| 548 | 'article', 'aside', 'audio', 'bdi', 'canvas', 'command',  | 
            ||
| 549 | 'datalist', 'details', 'dialog', 'embed', 'figure', 'figcaption',  | 
            ||
| 550 | 'footer', 'header', 'hgroup', 'keygen', 'mark', 'meter', 'nav',  | 
            ||
| 551 | 'output', 'progress', 'ruby', 'rt', 'rp', 'track', 'section',  | 
            ||
| 552 | 'source', 'summary', 'time', 'video', 'wbr'  | 
            ||
| 553 | );  | 
            ||
| 554 | |||
| 555 |             foreach ($tags as $tag) { | 
            ||
| 556 |                 if ($isHtml) { | 
            ||
| 557 | $elements = self::getElementsByCaseInsensitiveTagName(  | 
            ||
| 558 | $dom,  | 
            ||
| 559 | $tag  | 
            ||
| 560 | );  | 
            ||
| 561 |                 } else { | 
            ||
| 562 | $elements = $dom->getElementsByTagName($tag);  | 
            ||
| 563 | }  | 
            ||
| 564 | |||
| 565 |                 foreach ($elements as $element) { | 
            ||
| 566 | $nodes[] = $element;  | 
            ||
| 567 | }  | 
            ||
| 568 | }  | 
            ||
| 569 | |||
| 570 |             if (empty($nodes)) { | 
            ||
| 571 | return false;  | 
            ||
| 572 | }  | 
            ||
| 573 | }  | 
            ||
| 574 | |||
| 575 | // filter by attributes  | 
            ||
| 576 |         if ($options['attributes']) { | 
            ||
| 577 |             foreach ($nodes as $node) { | 
            ||
| 578 | $invalid = false;  | 
            ||
| 579 | |||
| 580 |                 foreach ($options['attributes'] as $name => $value) { | 
            ||
| 581 | // match by regexp if like "regexp:/foo/i"  | 
            ||
| 582 |                     if (preg_match('/^regexp\s*:\s*(.*)/i', $value, $matches)) { | 
            ||
| 583 |                         if (!preg_match($matches[1], $node->getAttribute($name))) { | 
            ||
| 584 | $invalid = true;  | 
            ||
| 585 | }  | 
            ||
| 586 | } // class can match only a part  | 
            ||
| 587 |                     elseif ($name == 'class') { | 
            ||
| 588 | // split to individual classes  | 
            ||
| 589 | $findClasses = explode(  | 
            ||
| 590 | ' ',  | 
            ||
| 591 |                             preg_replace("/\s+/", ' ', $value) | 
            ||
| 592 | );  | 
            ||
| 593 | |||
| 594 | $allClasses = explode(  | 
            ||
| 595 | ' ',  | 
            ||
| 596 |                             preg_replace("/\s+/", ' ', $node->getAttribute($name)) | 
            ||
| 597 | );  | 
            ||
| 598 | |||
| 599 | // make sure each class given is in the actual node  | 
            ||
| 600 |                         foreach ($findClasses as $findClass) { | 
            ||
| 601 |                             if (!in_array($findClass, $allClasses)) { | 
            ||
| 602 | $invalid = true;  | 
            ||
| 603 | }  | 
            ||
| 604 | }  | 
            ||
| 605 | } // match by exact string  | 
            ||
| 606 |                     else { | 
            ||
| 607 |                         if ($node->getAttribute($name) != $value) { | 
            ||
| 608 | $invalid = true;  | 
            ||
| 609 | }  | 
            ||
| 610 | }  | 
            ||
| 611 | }  | 
            ||
| 612 | |||
| 613 | // if every attribute given matched  | 
            ||
| 614 |                 if (!$invalid) { | 
            ||
| 615 | $filtered[] = $node;  | 
            ||
| 616 | }  | 
            ||
| 617 | }  | 
            ||
| 618 | |||
| 619 | $nodes = $filtered;  | 
            ||
| 620 | $filtered = array();  | 
            ||
| 621 | |||
| 622 |             if (empty($nodes)) { | 
            ||
| 623 | return false;  | 
            ||
| 624 | }  | 
            ||
| 625 | }  | 
            ||
| 626 | |||
| 627 | // filter by content  | 
            ||
| 628 |         if ($options['content'] !== null) { | 
            ||
| 629 |             foreach ($nodes as $node) { | 
            ||
| 630 | $invalid = false;  | 
            ||
| 631 | |||
| 632 | // match by regexp if like "regexp:/foo/i"  | 
            ||
| 633 |                 if (preg_match('/^regexp\s*:\s*(.*)/i', $options['content'], $matches)) { | 
            ||
| 634 |                     if (!preg_match($matches[1], self::getNodeText($node))) { | 
            ||
| 635 | $invalid = true;  | 
            ||
| 636 | }  | 
            ||
| 637 | } // match empty string  | 
            ||
| 638 |                 elseif ($options['content'] === '') { | 
            ||
| 639 |                     if (self::getNodeText($node) !== '') { | 
            ||
| 640 | $invalid = true;  | 
            ||
| 641 | }  | 
            ||
| 642 | } // match by exact string  | 
            ||
| 643 |                 elseif (strstr(self::getNodeText($node), $options['content']) === false) { | 
            ||
| 644 | $invalid = true;  | 
            ||
| 645 | }  | 
            ||
| 646 | |||
| 647 |                 if (!$invalid) { | 
            ||
| 648 | $filtered[] = $node;  | 
            ||
| 649 | }  | 
            ||
| 650 | }  | 
            ||
| 651 | |||
| 652 | $nodes = $filtered;  | 
            ||
| 653 | $filtered = array();  | 
            ||
| 654 | |||
| 655 |             if (empty($nodes)) { | 
            ||
| 656 | return false;  | 
            ||
| 657 | }  | 
            ||
| 658 | }  | 
            ||
| 659 | |||
| 660 | // filter by parent node  | 
            ||
| 661 |         if ($options['parent']) { | 
            ||
| 662 | $parentNodes = self::findNodes($dom, $options['parent'], $isHtml);  | 
            ||
| 663 | $parentNode = isset($parentNodes[0]) ? $parentNodes[0] : null;  | 
            ||
| 664 | |||
| 665 |             foreach ($nodes as $node) { | 
            ||
| 666 |                 if ($parentNode !== $node->parentNode) { | 
            ||
| 667 | continue;  | 
            ||
| 668 | }  | 
            ||
| 669 | |||
| 670 | $filtered[] = $node;  | 
            ||
| 671 | }  | 
            ||
| 672 | |||
| 673 | $nodes = $filtered;  | 
            ||
| 674 | $filtered = array();  | 
            ||
| 675 | |||
| 676 |             if (empty($nodes)) { | 
            ||
| 677 | return false;  | 
            ||
| 678 | }  | 
            ||
| 679 | }  | 
            ||
| 680 | |||
| 681 | // filter by child node  | 
            ||
| 682 |         if ($options['child']) { | 
            ||
| 683 | $childNodes = self::findNodes($dom, $options['child'], $isHtml);  | 
            ||
| 684 | $childNodes = !empty($childNodes) ? $childNodes : array();  | 
            ||
| 685 | |||
| 686 |             foreach ($nodes as $node) { | 
            ||
| 687 |                 foreach ($node->childNodes as $child) { | 
            ||
| 688 |                     foreach ($childNodes as $childNode) { | 
            ||
| 689 |                         if ($childNode === $child) { | 
            ||
| 690 | $filtered[] = $node;  | 
            ||
| 691 | }  | 
            ||
| 692 | }  | 
            ||
| 693 | }  | 
            ||
| 694 | }  | 
            ||
| 695 | |||
| 696 | $nodes = $filtered;  | 
            ||
| 697 | $filtered = array();  | 
            ||
| 698 | |||
| 699 |             if (empty($nodes)) { | 
            ||
| 700 | return false;  | 
            ||
| 701 | }  | 
            ||
| 702 | }  | 
            ||
| 703 | |||
| 704 | // filter by adjacent-sibling  | 
            ||
| 705 |         if ($options['adjacent-sibling']) { | 
            ||
| 706 | $adjacentSiblingNodes = self::findNodes($dom, $options['adjacent-sibling'], $isHtml);  | 
            ||
| 707 | $adjacentSiblingNodes = !empty($adjacentSiblingNodes) ? $adjacentSiblingNodes : array();  | 
            ||
| 708 | |||
| 709 |             foreach ($nodes as $node) { | 
            ||
| 710 | $sibling = $node;  | 
            ||
| 711 | |||
| 712 |                 while ($sibling = $sibling->nextSibling) { | 
            ||
| 713 |                     if ($sibling->nodeType !== XML_ELEMENT_NODE) { | 
            ||
| 714 | continue;  | 
            ||
| 715 | }  | 
            ||
| 716 | |||
| 717 |                     foreach ($adjacentSiblingNodes as $adjacentSiblingNode) { | 
            ||
| 718 |                         if ($sibling === $adjacentSiblingNode) { | 
            ||
| 719 | $filtered[] = $node;  | 
            ||
| 720 | break;  | 
            ||
| 721 | }  | 
            ||
| 722 | }  | 
            ||
| 723 | |||
| 724 | break;  | 
            ||
| 725 | }  | 
            ||
| 726 | }  | 
            ||
| 727 | |||
| 728 | $nodes = $filtered;  | 
            ||
| 729 | $filtered = array();  | 
            ||
| 730 | |||
| 731 |             if (empty($nodes)) { | 
            ||
| 732 | return false;  | 
            ||
| 733 | }  | 
            ||
| 734 | }  | 
            ||
| 735 | |||
| 736 | // filter by ancestor  | 
            ||
| 737 |         if ($options['ancestor']) { | 
            ||
| 738 | $ancestorNodes = self::findNodes($dom, $options['ancestor'], $isHtml);  | 
            ||
| 739 | $ancestorNode = isset($ancestorNodes[0]) ? $ancestorNodes[0] : null;  | 
            ||
| 740 | |||
| 741 |             foreach ($nodes as $node) { | 
            ||
| 742 | $parent = $node->parentNode;  | 
            ||
| 743 | |||
| 744 |                 while ($parent && $parent->nodeType != XML_HTML_DOCUMENT_NODE) { | 
            ||
| 745 |                     if ($parent === $ancestorNode) { | 
            ||
| 746 | $filtered[] = $node;  | 
            ||
| 747 | }  | 
            ||
| 748 | |||
| 749 | $parent = $parent->parentNode;  | 
            ||
| 750 | }  | 
            ||
| 751 | }  | 
            ||
| 752 | |||
| 753 | $nodes = $filtered;  | 
            ||
| 754 | $filtered = array();  | 
            ||
| 755 | |||
| 756 |             if (empty($nodes)) { | 
            ||
| 757 | return false;  | 
            ||
| 758 | }  | 
            ||
| 759 | }  | 
            ||
| 760 | |||
| 761 | // filter by descendant  | 
            ||
| 762 |         if ($options['descendant']) { | 
            ||
| 763 | $descendantNodes = self::findNodes($dom, $options['descendant'], $isHtml);  | 
            ||
| 764 | $descendantNodes = !empty($descendantNodes) ? $descendantNodes : array();  | 
            ||
| 765 | |||
| 766 |             foreach ($nodes as $node) { | 
            ||
| 767 |                 foreach (self::getDescendants($node) as $descendant) { | 
            ||
| 768 |                     foreach ($descendantNodes as $descendantNode) { | 
            ||
| 769 |                         if ($descendantNode === $descendant) { | 
            ||
| 770 | $filtered[] = $node;  | 
            ||
| 771 | }  | 
            ||
| 772 | }  | 
            ||
| 773 | }  | 
            ||
| 774 | }  | 
            ||
| 775 | |||
| 776 | $nodes = $filtered;  | 
            ||
| 777 | $filtered = array();  | 
            ||
| 778 | |||
| 779 |             if (empty($nodes)) { | 
            ||
| 780 | return false;  | 
            ||
| 781 | }  | 
            ||
| 782 | }  | 
            ||
| 783 | |||
| 784 | // filter by children  | 
            ||
| 785 |         if ($options['children']) { | 
            ||
| 786 |             $validChild   = array('count', 'greater_than', 'less_than', 'only'); | 
            ||
| 787 | $childOptions = self::assertValidKeys(  | 
            ||
| 788 | $options['children'],  | 
            ||
| 789 | $validChild  | 
            ||
| 790 | );  | 
            ||
| 791 | |||
| 792 |             foreach ($nodes as $node) { | 
            ||
| 793 | $childNodes = $node->childNodes;  | 
            ||
| 794 | |||
| 795 |                 foreach ($childNodes as $childNode) { | 
            ||
| 796 | if ($childNode->nodeType !== XML_CDATA_SECTION_NODE &&  | 
            ||
| 797 |                         $childNode->nodeType !== XML_TEXT_NODE) { | 
            ||
| 798 | $children[] = $childNode;  | 
            ||
| 799 | }  | 
            ||
| 800 | }  | 
            ||
| 801 | |||
| 802 | // we must have children to pass this filter  | 
            ||
| 803 |                 if (!empty($children)) { | 
            ||
| 804 | // exact count of children  | 
            ||
| 805 |                     if ($childOptions['count'] !== null) { | 
            ||
| 806 |                         if (count($children) !== $childOptions['count']) { | 
            ||
| 807 | break;  | 
            ||
| 808 | }  | 
            ||
| 809 | } // range count of children  | 
            ||
| 810 | elseif ($childOptions['less_than'] !== null &&  | 
            ||
| 811 |                             $childOptions['greater_than'] !== null) { | 
            ||
| 812 | if (count($children) >= $childOptions['less_than'] ||  | 
            ||
| 813 |                             count($children) <= $childOptions['greater_than']) { | 
            ||
| 814 | break;  | 
            ||
| 815 | }  | 
            ||
| 816 | } // less than a given count  | 
            ||
| 817 |                     elseif ($childOptions['less_than'] !== null) { | 
            ||
| 818 |                         if (count($children) >= $childOptions['less_than']) { | 
            ||
| 819 | break;  | 
            ||
| 820 | }  | 
            ||
| 821 | } // more than a given count  | 
            ||
| 822 |                     elseif ($childOptions['greater_than'] !== null) { | 
            ||
| 823 |                         if (count($children) <= $childOptions['greater_than']) { | 
            ||
| 824 | break;  | 
            ||
| 825 | }  | 
            ||
| 826 | }  | 
            ||
| 827 | |||
| 828 | // match each child against a specific tag  | 
            ||
| 829 |                     if ($childOptions['only']) { | 
            ||
| 830 | $onlyNodes = self::findNodes(  | 
            ||
| 831 | $dom,  | 
            ||
| 832 | $childOptions['only'],  | 
            ||
| 833 | $isHtml  | 
            ||
| 834 | );  | 
            ||
| 835 | |||
| 836 | // try to match each child to one of the 'only' nodes  | 
            ||
| 837 |                         foreach ($children as $child) { | 
            ||
| 838 | $matched = false;  | 
            ||
| 839 | |||
| 840 |                             foreach ($onlyNodes as $onlyNode) { | 
            ||
| 841 |                                 if ($onlyNode === $child) { | 
            ||
| 842 | $matched = true;  | 
            ||
| 843 | }  | 
            ||
| 844 | }  | 
            ||
| 845 | |||
| 846 |                             if (!$matched) { | 
            ||
| 847 | break 2;  | 
            ||
| 848 | }  | 
            ||
| 849 | }  | 
            ||
| 850 | }  | 
            ||
| 851 | |||
| 852 | $filtered[] = $node;  | 
            ||
| 853 | }  | 
            ||
| 854 | }  | 
            ||
| 855 | |||
| 856 | $nodes = $filtered;  | 
            ||
| 857 | |||
| 858 |             if (empty($nodes)) { | 
            ||
| 859 | return;  | 
            ||
| 860 | }  | 
            ||
| 861 | }  | 
            ||
| 862 | |||
| 863 | // return the first node that matches all criteria  | 
            ||
| 864 | return !empty($nodes) ? $nodes : array();  | 
            ||
| 865 | }  | 
            ||
| 866 | |||
| 944 |