<?php # 堆代码 duidaima.com $connect = mysqli_connect("localhost", "root", "123456", "blog", "3306") or die("数据库连接失败!"); $connect->set_charset("utf8"); $id = 1; $sql = "SELECT * FROM article WHERE id = $id"; $query = mysqli_query($connect, $sql); if (!$query) { die("数据库查询失败!"); } $assoc = $query->fetch_assoc(); var_dump($assoc);上面的写法有一些缺点,有一种更好的方式是使用PDO,扩展性更强,而且可以使用预处理防止SQL注入:
<?php try { $pdo = new PDO("mysql:host=localhost;dbname=blog", "root", "123456"); } catch (PDOException $exception) { echo "Connect Failed" . $exception->getMessage(); } $pdo->exec("set names utf8"); $id = 1; $prepare = $pdo->prepare("SELECT * FROM article WHERE id = ?"); $prepare->execute(array($id)); while ($row = $prepare->fetch()) { var_dump($row); }不过实际开发中,大家都是使用一些封装好的类和方法,比如laravel框架里面称之为查询构造器,我们可以使用这样方法去查询数据库:
<?php $users = DB::table('users')->get(); $price = DB::table('orders')->where('finalized', 1)->avg('price'); $users = DB::table('users') ->join('contacts', 'users.id', '=', 'contacts.user_id') ->join('orders', 'users.id', '=', 'orders.user_id') ->select('users.*', 'contacts.phone', 'orders.price') ->get(); $orders = DB::table('orders') ->select('department', DB::raw('SUM(price) as total_sales')) ->groupBy('department') ->havingRaw('SUM(price) > 2500') ->get();还有比如说TP框架里面M方法,这些类和方法大大简化了查询操作,但本质上还是拼SQL,只不过调用的时候看起来更像面向对象,方便很多。但是这些并不是真正意义上的ORM,最多只算得上是O(object),它只是把数据库查询操作对象化了,但是没有解决对象之间的关系问题!
{ "require": { "doctrine/orm": "^2.6.2", "symfony/yaml": "2.*" } }2.在项目根目录创建一个bootstrap.php文件:
<?php // bootstrap.php use Doctrine\ORM\Tools\Setup; use Doctrine\ORM\EntityManager; require_once "vendor/autoload.php"; // Create a simple "default" Doctrine ORM configuration for Annotations $isDevMode = true; $config = Setup::createAnnotationMetadataConfiguration(array(__DIR__."/src"), $isDevMode); // or if you prefer yaml or XML //$config = Setup::createXMLMetadataConfiguration(array(__DIR__."/config/xml"), $isDevMode); //$config = Setup::createYAMLMetadataConfiguration(array(__DIR__."/config/yaml"), $isDevMode); // database configuration parameters $conn = array( 'dbname' => 'blog', 'user' => 'root', 'password' => '123456', 'host' => 'localhost', 'driver' => 'pdo_mysql', 'charset' => 'utf8', ); // obtaining the entity manager $entityManager = EntityManager::create($conn, $config);这里面有一些需要注意的地方,$idDevMode是配置是否开发模式。
<?php // cli-config.php require_once "bootstrap.php"; return \Doctrine\ORM\Tools\Console\ConsoleRunner::createHelperSet($entityManager);这样就可以使用命令行工具执行一些操作,比如说生成数据表,更新数据表
<?php namespace App; /** * @Entity @Table(name="products",options={"collate"="utf8mb4_unicode_ci", "charset"="utf8mb4"}) * Class Product * @package App */ class Product { /** * @ID @Column(type="integer") @GenerateDValue * @var int */ protected $id; /** * @Column(type="string") * @var string */ protected $name; /** * @return int */ ......more code }后面的setter和getter这里省略了,如果有人对 annotation 这种注解方法比较熟悉的话应该可以看懂上面那些注释的意思。首先在类的注释上,使用了@Entity表明这是一个数据库实体。@Table指定了表名,@ID表明的是主键,@Column表明是数据表字段,使用type声明了类型!
The following SQL statements will be executed: CREATE TABLE products (id INT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB; Updating database schema... 1 query was executed [OK] Database schema updated successfully!使用这种方式建表不用去写SQL语句,无论是mysql还是sql server,或者oracle,都没问题,一键迁移,ORM抹平了数据库之间的差异!
<?php require "vendor/autoload.php"; require "bootstrap.php"; $product = new \App\Product(); $product->setName("ORM的应用"); $entityManager->persist($product); $entityManager->flush(); echo "Created Product Success with ID: ".$product->getId(); var_dump($product);可以看出来这是一个完全OOP的写法,是先实例化一个数据表实体,然后通过setter去设置去属性,最后调用persist和flush持久化数据库里面。
<?php //查询所有 $productRepository = $entityManager->getRepository('\App\Product'); $products = $productRepository->findAll(); foreach ($products as $product) { var_dump($product); var_dump($product->getName()); } //查询单个 $id = 3; $product = $entityManager->find('Product', $id); if ($product === null) { echo "No product found.\n"; exit(1); } var_dump($product);如果想对数据进行修改也很简单,比如在上面的例子里面,我们查询出id为3的数据,现在我们想修改这条数据:
<?php $product->setName("ORM更新数据"); $entityManager->flush();我们只需调用这个对象的setter方法,然后flush即可!
第三种: 新建一个中间表,用来维护2个表之间的关系,中间表一般用来维护多对多的关系,但是也可以用于1对多的关系,这时候查询和修改都比较复杂,好处就是很容易扩展成多对多关系!
<?php namespace App; /** * @Entity @Table(name="comments",options={"collate"="utf8mb4_unicode_ci", "charset"="utf8mb4"}) * Class Product * @package App */ class Comment { /** * 这里通过注释设置了需要映射的实体和对应的字段 * @ManyToOne(targetEntity="Product", inversedBy="comments") * @JoinColumn(name="product_id", referenceColumnName="id") * @var Product */ protected $product; /** * @return Product */ public function getProduct(): Product { return $this->product; } /** * @param Product $product * @return self */ public function setProduct(Product $product): self { $this->product = $product; return $this; } /** * @ID @Column(type="integer") @GenerateDValue * @var int */ protected $id; /** * @Column(type="string") * @var string */ protected $content; .......more code }但是多了一个属性 product, 因为这种1对多的关系对评论来说就是一个评论拥有一个产品,但是一个产品可以拥有多个评论。同理,我们就需要对 product 实体做一些改动,加入了一个comments属性和一些注解!
<?php /** * @oneToMany(targetEntity="Comment", mappedBy="product") * @var */ protected $comments; public function __construct() { $this->comments = new ArrayCollection(); }执行 vendor/bin/doctrine orm:schema-tool:update --force --dump-sql更新数据库, 执行之后你会发现comments表会多一个product_id字段, 同时还会多出一个外键索引!
<?php $id = 3; $product = $entityManager->find('\App\Product', $id); $comment = new \App\Comment(); $comment->setContent("这是一条评论!"); $comment->setProduct($product); $entityManager->persist($comment); $entityManager->flush();执行以上代码,查看数据表你会发现comments表会自动增加一条记录,其product_id为3,在代码里面我们并没有手动去设置product_id,ORM替我们自动完成了这些操作!下面再看查询一个产品的所有评论,操作也是相当简单的:
<?php $id = 3; $product = $entityManager->find('\App\Product', $id); $comments = $product->getComments()->toArray();