[英]Can I make this search function more efficient?
I am getting a list of users to display on a page using the following code in members.php
: 我正在使用members.php
的以下代码获取要显示在页面上的用户列表:
$users = $user->getUsers($_GET['skill'], $_GET['hometowm'], $_GET['county']);
members.php
displays all members members.php
显示所有成员 members.php?skill=Foo
displays users with that skill members.php?skill=Foo
用户显示该技能 members.php?hometown=Foo
displays users of hometown "Foo" members.php?hometown=Foo
显示家乡“ Foo”的用户 members.php?county=Foo
display users of county (AKA state in US) members.php?county=Foo
显示县(美国的AKA州)的用户 members.php?skill=Foo&hometown=Foo
displays users of skill and hometown members.php?skill=Foo&hometown=Foo
显示技能和家乡的用户 members.php?skill=Foo&county=Foo
displays users of skill and county members.php?skill=Foo&county=Foo
显示技能和县的用户 Here is what I'd like to know: Is there a way I can shorten the amount of if
statements or make them more efficient? 我想知道的是:有没有一种方法可以缩短if
语句的数量或使它们更有效? Am I doing it correctly? 我做得对吗? Because I don't like the fact I have so many parameters especially when I want to expand. 因为我不喜欢这样的事实,我有很多参数,尤其是当我要扩展时。
**User.class.php**
public function getUsers($skill = null, $hometown = null, $county = null) {
$user_table = $this->cfg['users_table']['table'];
# Search Skill
if ($skill != null && $hometown == null && $county == null) {
$sql = 'SELECT skills.Title, users_skills.SkillId, users.*
FROM users INNER JOIN (skills INNER JOIN users_skills ON skills.SkillId = users_skills.SkillId) ON users.UserId = users_skills.UserId
WHERE (((skills.Title)="' . $skill . '"))';
# Search Hometown
} else if ($hometown != null && $skill == null && $county == null) {
$sql = 'SELECT * FROM users WHERE HomeTown = "' . $hometown . '"';
# Search County
} else if ($county != null && $skill == null && $hometown == null) {
$sql = 'SELECT * FROM users WHERE county = "' . $county . '"';
# Search Skill and Hometown
} else if ($skill != null && $hometown != null && $county == null) {
//sql
# Search Skill and County
} else if($skill != null && $county != null && $hometown == null){
} else {
$sql = "SELECT * FROM " . $user_table;
}
$stmt = $this->db->prepare($sql);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
Thanks. 谢谢。
There are actually two issues here. 实际上,这里有两个问题。 The first is that your interface design is too specific. 首先是您的界面设计过于具体。 The other is that you're mixing the data model with the database access layer, and that's making your code more complicated. 另一个是您将数据模型与数据库访问层混合在一起,这使您的代码更加复杂。
I've skipped some details in my examples for brevity (and the code is untested), but I presume you can fill in the gaps. 为了简洁起见,我在示例中跳过了一些细节(并且代码未经测试),但是我想您可以填补空白。
The first order of business is to make your interface more general. 首先要做的是使您的界面更通用。 Instead of using one method that does everything, split county
, skill
, etc. into different methods: 与其使用一种无所不能的方法,而是将county
, skill
等拆分为不同的方法:
class userFilter
{
protected $db;
protected $params;
protected function __construct()
{
$this->db = new database_connection();
}
public static function create()
{
return new userFilter();
}
public function addCounty($county)
{
// For simplicity, 'county' is the column name
$this->params['county'][] = $county;
// Return $this to enable method chaining, used below
return $this;
}
public function addSkill($skill)
{
$this->params['skill'][] = $skill;
return $this;
}
public function addHometown($hometown)
{
return $this;
}
public function fetchUsers()
{
return '$data';
}
}
With the above interface, you can optionally add any number of parameters, and each (potentially) has its own logic associated with validating input, writing SQL conditions, etc. 使用上面的接口,您可以选择添加任意数量的参数,并且每个参数(潜在地)都有自己的逻辑,这些逻辑与验证输入,编写SQL条件等相关。
The hard part of this solution is writing the actual SQL. 该解决方案的难点是编写实际的SQL。 For that, you need to know a few things: 为此,您需要了解以下几点:
SELECT
clause)? 您想要哪些列( SELECT
子句)? WHERE
clause)? 您想要哪些行( WHERE
子句)? The easy way to solve this problems is by using arrays, because you can easily foreach
over them to include whichever may be specified, and you can use their key=>value pairing to maintain associations with respect to your database schema. 解决此问题的简单方法是使用数组,因为您可以轻松地foreach
它们以包括可能指定的任何一个,并且可以使用它们的key => value配对来维护与数据库模式的关联。
Now when you go to write the query for fetchUsers()
you can iterate over $this->params
using array_keys($this->params)
as the column names and $this->params
as the data. 现在,当您编写对fetchUsers()
的查询时,可以使用array_keys($this->params)
作为列名和$this->params
作为数据遍历$this->params
。 That might look something like this: 可能看起来像这样:
// Select all columns present in $this->params
$sql = 'SELECT id, '.implode(', ', array_keys($this->params));
$sql .= 'FROM table_name WHERE ';
$where = array()
foreach($this->params as $column => $ids){
$where[] = $column . ' IN ('.implode(', ', $ids).')';
}
$sql .= implode(' AND ', $where);
With a more complicated schema that requires joins, you may need a switch to handle each join and join condition, or you may find a way to cram that into an array. 对于需要联接的更复杂的架构,您可能需要一个开关来处理每个联接和联接条件,或者您可以找到一种将其塞入数组的方法。 You'll also need extra logic to make sure you don't add an empty WHERE
clause or other silly things, but the meat of it is there. 您还需要额外的逻辑以确保您没有添加空的WHERE
子句或其他愚蠢的东西,但是它的实质是存在的。
When the above code is self-contained in a class, fetching data is very simple. 当上述代码独立包含在类中时,获取数据非常简单。
$results = userFilter::create()
->addCounty($county)
->addHometown($hometown)
->addSkill($skill)
->addSkill($skill)
->addSkill($skill)
->fetchUsers();
If you want to conditionally use certain methods: 如果要有条件地使用某些方法:
$userFilter = userFilter::create();
if(isset($_GET['hometown'])){
$userFilter->addHometown($_GET['hometown']);
}
if(isset($_GET['skill'])){
$userFilter->addSkill($_GET['skill']);
}
$userFilter->fetchUsers();
I often end up with a construction about like this (approximately): 我经常最终得到一个大约这样的构造:
$select = array("users.*"); // columns
$where = array("1=1"); // WHERE clauses
$values = array(); // values to bind
$join = array(); // additional joins
if ($skill) {
$join[] = " JOIN users_skills USING (userid) JOIN skills USING (skillid)";
$where[] = "skills.title = ?";
$values[] = $skill;
}
if ($hometown) {
$where[] = "hometown = ?";
$values[] = $hometown;
}
if ($county) {
$where[] = "county = ?";
$values[] = $county;
}
$parenthesise = function($value) { return "($value)"; };
$sql = "SELECT ".implode(",", $select)
." FROM users ".implode("", $join)
." WHERE ".implode(" AND ", array_map($parenthesise, $where));
// now prepare $sql and execute with $values
在实际的查询或存储过程中执行逻辑将为您提供RDBMS提供的优化,并且返回的记录更少,消耗的资源更少,并使您的工作更少。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.