Finding the Bayesian estimates for the top 100 products on NutraPlanet This code fetches reviews for the top 100 products on NutraPlanet, finds the Bayesian estimate for each average review, then prints out all reviews sorted by that Bayesian estimate.

How can I improve this code (correctness, elegance, best practices, etc)?

&lt;?php

// echo "Remove exit from script to run."; exit;

define("MINIMUM_NUMBER_OF_VOTES_TO_SAVE_PRODUCT", 2);

$locations = array("http://www.nutraplanet.com/top_100");

$reviewUrlFragments = array_unique(getReviewUrlFragments($locations));

$products = getProducts(
        $reviewUrlFragments, 
        MINIMUM_NUMBER_OF_VOTES_TO_SAVE_PRODUCT);

calculateBayesianEstimate($products);

usort($products, function ($a, $b) {
    if ($a["bayesian_estimate"] == $b["bayesian_estimate"]) {
        return 0;
    }
    return ($a["bayesian_estimate"] &lt; $b["bayesian_estimate"]) ? 1 : -1;
});

printReviews($products);

function getReviewUrlFragments($locations) {
    $reviewUrlFragments = array();

    foreach($locations as $location) {    
        $page = @file_get_contents($location);

        preg_match_all("%/product/(.*?)\.html%is", $page, $matches);

        $reviewUrlFragments = array_merge($reviewUrlFragments, $matches[1]);
    }

    return $reviewUrlFragments;
}

function getProducts($productReviewUrlFragments, $minimumNumberOfVotesToSaveProduct) {
    $products = array();

    foreach($productReviewUrlFragments as $productReviewUrlFragment) {
        $reviewUrl = "http://www.nutraplanet.com/manufacturer/" . $productReviewUrlFragment . "/reviews";

        $page = @file_get_contents($reviewUrl);

        preg_match_all("%&lt;td&gt;&amp;nbsp;&lt;i&gt;(.*?)&lt;/i&gt;&lt;/td&gt;%is", $page, $matches);

        $product = array();
        $product['name'] = "http://www.nutraplanet.com/product/".$productReviewUrlFragment.".html";

        $votes = getVotes($matches[1]);    

        $product["vote_distribution"] = $votes["votes"];
        $product["review_average"] = $votes["average"];
        $product["num_votes"] = $votes["num_votes"];

        // Only add if there is a vote for the product
        if ($product["num_votes"] &gt;= $minimumNumberOfVotesToSaveProduct) {
            $products[] = $product;
        }
    }

    return $products;
}

function getVotes($match) {
    $votes = array();  
    $sum_votes = 0;
    $total_votes = 0;
    $vote_star = 1;

    // In ascending order, 1-star to 5
    foreach($match as $vote_count) {
        $votes[] = $vote_count;
        $total_votes += $vote_count;
        $sum_votes += ($vote_count * $vote_star++);
    }

    $product["votes"] = $votes;
    $product["average"] = ($total_votes &lt; 1) ? 0 : ($sum_votes / $total_votes);
    $product["num_votes"] = $total_votes;

    return $product;
}

function calculateBayesianEstimate(&amp;$products) {
    // See bottom of page: http://www.imdb.com/chart/top
    $m = getMinNumberOfVotes($products);
    $C = getAverageReviewAverage($products);        

    for ($i = 0, $len = count($products); $i &lt; $len; $i++) {
        $R = $products[$i]["review_average"];
        $v = $products[$i]["num_votes"];
        $products[$i]["bayesian_estimate"] = (($v / ($v+$m)) * $R) + (($m / ($v+$m)) * $C);
    }
}

function getAverageReviewAverage($products) {
    $total = 0;

    foreach($products as $product) {
        $total += $product["review_average"];
    }

    return $total / count($products);
}

function getMinNumberOfVotes($products) {
    foreach($products as $product) {
        if (!isset($minVote) || ($product["num_votes"] &lt; $minVote)) {
            $minVote = $product["num_votes"];
        }
    }

    if (!isset($minVote)) {
        $minVote = 0;
    }

    return $minVote;
}

function printReviews($products) {
    echo "&lt;table&gt;";
    foreach($products as $product) {
        $product["vote_distribution"] = implode("&lt;/td&gt;&lt;td&gt;", $product["vote_distribution"]);
        $product = implode("&lt;/td&gt;&lt;td&gt;", $product);
        echo "&lt;tr&gt;&lt;td&gt;" . $product . "&lt;/td&gt;&lt;/tr&gt;";
    }
    echo "&lt;table&gt;";
}
?&gt;
I just put this together, so I haven't tested it or anything, there might be bugs and someone else PLEASE come along and improve upon it, but I think this might be a good starting point to answering this question:

OOP version of OP's code:



$ReviewPrinter = new ReviewPrinter("http://www.nutraplanet.com/top_100", 2);
echo $ReviewPrinter-&gt;printReviews();



class ReviewPrinter{
    public $products;
    public $locations;
    public $reviewUrlFragments;
    public $minimumNumberOfVotesToSaveProduct;

    public function __construct($locations, $minimumNumberOfVotesToSaveProduct){
        if(empty($locations) || empty($minimumNumberOfVotesToSaveProduct)){
            return false;
        } else {
            $this-&gt;minimumNumberOfVotesToSaveProduct = $minimumNumberOfVotesToSaveProduct;
            $this-&gt;locations = array($locations);
            $this-&gt;setReviewUrlFragments();
            $this-&gt;products = $this-&gt;getProducts();
            $this-&gt;calculateBayesianEstimate();
            $this-&gt;sortProducts();
        }
    }

    public function sortProducts(){
        usort($this-&gt;products, function ($a, $b) {
            if ($a["bayesian_estimate"] == $b["bayesian_estimate"]) {
                return 0;
            }
            return (($a["bayesian_estimate"] &lt; $b["bayesian_estimate"]) ? 1 : -1);
        });
    }

    public function setReviewUrlFragments(){
        $localReviewUrlFragments = array();

        foreach($this-&gt;locations as $location) {
            preg_match_all("%/product/(.*?)\.html%is", @file_get_contents($location), $matches);
            $localReviewUrlFragments = array_merge($localReviewUrlFragments, $matches[1]);
        }

        $this-&gt;reviewUrlFragments = array_unique($localReviewUrlFragments);
    }

    public function getProducts(){
        $functionScopeProducts = array();

        foreach($this-&gt;reviewUrlFragments as $productReviewUrlFragment) {
            $reviewUrl = "http://www.nutraplanet.com/manufacturer/" . $productReviewUrlFragment . "/reviews";

            preg_match_all("%&lt;td&gt;&amp;nbsp;&lt;i&gt;(.*?)&lt;/i&gt;&lt;/td&gt;%is", @file_get_contents($reviewUrl), $matches);

            $localProducts = array();
            $localProducts['name'] = "http://www.nutraplanet.com/product/".$productReviewUrlFragment.".html";

            $votes = $this-&gt;getVotes($matches[1]);    

            $localProducts["vote_distribution"] = $votes["votes"];
            $localProducts["review_average"] = $votes["average"];
            $localProducts["num_votes"] = $votes["num_votes"];

            // Only add if there is a vote for the product
            if ($localProducts["num_votes"] &gt;= $this-&gt;minimumNumberOfVotesToSaveProduct) {
                $functionScopeProducts[] = $localProducts;
            }
        }

        return $functionScopeProducts;
    }

    public function getVotes($match){
        $votes = array();  
        $sum_votes = 0;
        $total_votes = 0;
        $vote_star = 1;

        // In ascending order, 1-star to 5
        foreach($match as $vote_count) {
            $votes[] = $vote_count;
            $total_votes += $vote_count;
            $sum_votes += ($vote_count * $vote_star++);
        }

        $product["votes"] = $votes;
        $product["average"] = ($total_votes &lt; 1) ? 0 : ($sum_votes / $total_votes);
        $product["num_votes"] = $total_votes;

        return $product;
    }

    public function calculateBayesianEstimate(){    
        /**
         * Algorithm used:  (WR) = (v ÷ (v+m)) × R + (m ÷ (v+m)) × C 
         * where:
         * WR = Weighted rating
         * R  = Average rating
         * v  = Number of votes
         * m  = Minimum votes required 
         * C  = Mean vote across the whole report
         */
        $m = $this-&gt;getMinNumberOfVotes();
        $C = $this-&gt;getAverageReviewAverage();        

        for ($i = 0, $len = count(&amp;$this-&gt;products); $i &lt; $len; $i++) {
            $R = &amp;$this-&gt;products[$i]["review_average"];
            $v = &amp;$this-&gt;products[$i]["num_votes"];
            &amp;$this-&gt;products[$i]["bayesian_estimate"] = (($v / ($v+$m)) * $R) + (($m / ($v+$m)) * $C);
        }
    }

    public function getAverageReviewAverage(){
        $total = 0;

        foreach($this-&gt;products as $product) {
            $total += $product["review_average"];
        }

        return $total / count($this-&gt;products);
    }

    public function getMinNumberOfVotes(){
        # NOTE: Where is $minVote set or created? 
        foreach($this-&gt;products as $product) {
            if (!isset($minVote) || ($product["num_votes"] &lt; $minVote)) {
                $minVote = $product["num_votes"];
            }
        }

        if (!isset($minVote)) {
            $minVote = 0;
        }

        return $minVote;
    }

    public function printReviews(){
        $output = "&lt;table&gt;";
        foreach($this-&gt;products as $product) {
            $product["vote_distribution"] = implode("&lt;/td&gt;&lt;td&gt;", $product["vote_distribution"]);
            $product = implode("&lt;/td&gt;&lt;td&gt;", $product);
            $output .= "&lt;tr&gt;&lt;td&gt;" . $product . "&lt;/td&gt;&lt;/tr&gt;";
        }
        $output .= "&lt;table&gt;";

        return $output;
    }
}


Obviously, there should be separation of concerns, which this does not implement, etc. 

++++
EDIT
++++

Implemented comments 



// Usage:
$ReviewPrinter = new ReviewPrinter("http://www.nutraplanet.com/top_100", 2);
echo $ReviewPrinter-&gt;printReviews();



class ReviewPrinter{
    private $products;
    private $locations;
    private $reviewUrlFragments;
    private $minimumNumberOfVotesToSaveProduct;

    public function __construct($locations, $minimumNumberOfVotesToSaveProduct){
        if(empty($locations) || empty($minimumNumberOfVotesToSaveProduct)){
            $c = 2 - (empty($locations) ? 1 : 0) - (empty($minimumNumberOfVotesToSaveProduct) ? 1 : 0);
            throw new Exception("Construct expects 2 parameters, $c given.");
        } else {
            $this-&gt;minimumNumberOfVotesToSaveProduct = $minimumNumberOfVotesToSaveProduct;
            $this-&gt;locations = array($locations);
            $this-&gt;setReviewUrlFragments();
            $this-&gt;products = $this-&gt;getProducts();
            $this-&gt;calculateBayesianEstimate();
            $this-&gt;sortProducts();
        }
    }

    private function sortProducts(){
        usort($this-&gt;products, function ($a, $b) {
            if ($a["bayesian_estimate"] == $b["bayesian_estimate"]) {
                return 0;
            }
            return (($a["bayesian_estimate"] &lt; $b["bayesian_estimate"]) ? 1 : -1);
        });
    }

    private function setReviewUrlFragments(){
        $localReviewUrlFragments = array();

        foreach($this-&gt;locations as $location) {
            preg_match_all("%/product/(.*?)\.html%is", @file_get_contents($location), $matches);
            $localReviewUrlFragments = array_merge($localReviewUrlFragments, $matches[1]);
        }

        $this-&gt;reviewUrlFragments = array_unique($localReviewUrlFragments);
    }

    private function getProducts(){
        $functionScopeProducts = array();

        foreach($this-&gt;reviewUrlFragments as $productReviewUrlFragment) {
            $reviewUrl = "http://www.nutraplanet.com/manufacturer/" . $productReviewUrlFragment . "/reviews";

            preg_match_all("%&lt;td&gt;&amp;nbsp;&lt;i&gt;(.*?)&lt;/i&gt;&lt;/td&gt;%is", @file_get_contents($reviewUrl), $matches);

            $localProducts = array();
            $localProducts['name'] = "http://www.nutraplanet.com/product/".$productReviewUrlFragment.".html";

            $votes = $this-&gt;getVotes($matches[1]);    

            $localProducts["vote_distribution"] = $votes["votes"];
            $localProducts["review_average"] = $votes["average"];
            $localProducts["num_votes"] = $votes["num_votes"];

            // Only add if there is a vote for the product
            if ($localProducts["num_votes"] &gt;= $this-&gt;minimumNumberOfVotesToSaveProduct) {
                $functionScopeProducts[] = $localProducts;
            }
        }

        return $functionScopeProducts;
    }

    private function getVotes($match){
        $votes = array();  
        $sum_votes = 0;
        $total_votes = 0;
        $vote_star = 1;

        // In ascending order, 1-star to 5
        foreach($match as $vote_count) {
            $votes[] = $vote_count;
            $total_votes += $vote_count;
            $sum_votes += ($vote_count * $vote_star++);
        }

        $product["votes"] = $votes;
        $product["average"] = ($total_votes &lt; 1) ? 0 : ($sum_votes / $total_votes);
        $product["num_votes"] = $total_votes;

        return $product;
    }

    private function calculateBayesianEstimate(){    
        /**
         * Algorithm used:  (WR) = (v ÷ (v+m)) × R + (m ÷ (v+m)) × C 
         * where:
         * WR = Weighted rating
         * R  = Average rating
         * v  = Number of votes
         * m  = Minimum votes required 
         * C  = Mean vote across the whole report
         */
        $m = $this-&gt;getMinNumberOfVotes();
        $C = $this-&gt;getAverageReviewAverage();        

        for ($i = 0, $len = count(&amp;$this-&gt;products); $i &lt; $len; $i++) {
            $R = &amp;$this-&gt;products[$i]["review_average"];
            $v = &amp;$this-&gt;products[$i]["num_votes"];
            &amp;$this-&gt;products[$i]["bayesian_estimate"] = (($v / ($v+$m)) * $R) + (($m / ($v+$m)) * $C);
        }
    }

    private function getAverageReviewAverage(){
        $total = 0;

        foreach($this-&gt;products as $product) {
            $total += $product["review_average"];
        }

        return $total / count($this-&gt;products);
    }

    private function getMinNumberOfVotes(){
        # NOTE: Where is $minVote set or created? 
        foreach($this-&gt;products as $product) {
            if (!isset($minVote) || ($product["num_votes"] &lt; $minVote)) {
                $minVote = $product["num_votes"];
            }
        }

        if (!isset($minVote)) {
            $minVote = 0;
        }

        return $minVote;
    }

    public function printReviews(){
        $output = "&lt;table&gt;";
        foreach($this-&gt;products as $product) {
            $product["vote_distribution"] = implode("&lt;/td&gt;&lt;td&gt;", $product["vote_distribution"]);
            $product = implode("&lt;/td&gt;&lt;td&gt;", $product);
            $output .= "&lt;tr&gt;&lt;td&gt;" . $product . "&lt;/td&gt;&lt;/tr&gt;";
        }
        $output .= "&lt;table&gt;";

        return $output;
    }
}