序文
Laravel フレームワークコンポーネント化された設計と設計の適切な使用のためパターンにより、フレームワーク自体が簡潔になり、拡張が容易になります。 ThinkPHP の統合関数フレームワーク (すべての関数を使用する、または関数を使用しない) とは異なり、Laravel ではコンポーザー ツールを使用してパッケージを管理し、関数を追加したい場合はコンポーネントを直接追加できます。たとえば、クローラーを作成し、ページ コレクション コンポーネントを使用する場合: composer require jaeger/querylist
この記事では、Laravel で頻繁に使用される PHP の機能と新しい構文を簡単に紹介します。詳細についてはそれを参照してください。
コンポーネントベースの開発
Laravel は、PSR-4 仕様に準拠したコンポーザー ツールのおかげでコンポーネントベースの開発を実行します。このツールは、名前空間と自動読み込みを使用してプロジェクト ファイルを整理します。詳細: Composer の自動読み込みメカニズム
名前空間
名前の競合
チーム内で共同作業し、サードパーティに依存するコードを導入する場合、クラス、関数、インターフェイスが重複して表示されることがよくあります。名前。例:
<?php # google.php class User { private $name; }
<?php # mine.php // 引入第三方依赖 include 'google.php'; class User { private $name; } $user = new User(); // 命名冲突
クラス User
が同時に定義されているため、名前の競合が発生します:
名前の競合を回避する と 名前を短くする という 2 つの機能があることを確認してください。たとえば、名前空間を使用した後:
<?php # google.php namespace Google; // 模拟第三方依赖 class User { private $name = 'google'; public function getName() { echo $this->name . PHP_EOL; } }
<?php # mine.php namespace Mine; // 导入并命名别名 use Google as G; // 导入文件使得 google.php 命名空间变为 mine.php 的子命名空间 include 'google.php'; /* 避免了命名冲突 */ class User { private $name = 'mine'; public function getName() { echo $this->name . PHP_EOL; } } /* 保持了命名简短 */ // 如果没有命名空间,为了类名也不冲突,可能会出现这种函数名 // $user = new Google_User(); // Zend 风格并不提倡 $user = new G\User(); // 为了函数名也不冲突,可能会出现这种函数名 // $user->google_get_name() $user->getName(); $user = new User(); $user->getName();実行:
$ php demo.php google minePSR仕様実際、名前空間はファイル名とは何の関係もありませんが、 PSR 標準要件: 名前空間はファイル パスと一致し、ファイル名はクラス名と一致します。たとえば、
laravel-demo/app/Http/Controllers/Auth/LoginController.php はデフォルトで Laravel によって生成され、その名前空間は
App\Http\Controllers\Auth & クラス名
LoginController
mine.php と
google.php は両方とも
User.php という名前にする必要があります。
__NAMESPACE__ マジック定数
...
// $user = new User();
$user = new namespace\User(); // 值为当前命名空间
$user->getName();
echo __NAMESPACE__ . PHP_EOL; // 直接获取当前命名空间字符串 // 输出 Mine
3 つの名前空間のインポート<?php namespace CurrentNameSpace;
// 不包含前缀
$user = new User(); # CurrentNameSpace\User();
// 指定前缀
$user = new Google\User(); # CurrentNameSpace\Google\User();
// 根前缀
$user = new \Google\User(); # \Google\User();
グローバル名前空間参照クラスの場合、Ifこの関数では名前空間が指定されていないため、デフォルトでは __NAMESPACE__ で検索されます。グローバル クラスを参照するには:
<?php namespace Demo; // 均不会被使用到 function strlen() {} const INI_ALL = 3; class Exception {} $a = \strlen('hi'); // 调用全局函数 strlen $b = \CREDITS_GROUP; // 访问全局常量 CREDITS_GROUP $c = new \Exception('error'); // 实例化全局类 Exception複数のインポートと複数の名前空間
// use 可一次导入多个命名空间
use Google,
Microsoft;
// 良好实践:每行一个 use
use Google;
use Microsoft;
<?php // 一个文件可定义多个命名空间
namespace Google {
class User {}
}
namespace Microsoft {
class User {}
}
// 良好实践:“一个文件一个类”
定数と関数のインポートPHP 5.6 以降では、use function と
use const 関数と定数をそれぞれインポートします。使用:
# google.php const CEO = 'Sundar Pichai'; function getMarketValue() { echo '770 billion dollars' . PHP_EOL; }
# mine.php use function Google\getMarketValue as thirdMarketValue; use const Google\CEO as third_CEO; thirdMarketValue(); echo third_CEO;実行:
$ php mine.php google 770 billion dollars Sundar Pichaimine Mineファイルに含まれる手動読み込み指定したファイルを導入するには、
include または
require を使用します (リテラル解釈) require エラーはコンパイル エラーを報告し、スクリプトを中断しますが、include エラーはコンパイル エラーを報告するだけであることに注意してください。警告が表示され、スクリプトは引き続き実行されます。
include_path で指定されたディレクトリが検索されます。見つからない場合は、現在のディレクトリが検索されます:
<?php // 引入的是 /usr/share/php/System.php include 'System.php';自動ロード
void __autoload(string $class) はクラスを自動的にロードできますが、通常は spl_autoload_register を使用して手動で登録します。 <pre class="brush:php;toolbar:false"><?php // 自动加载子目录 classes 下 *.class.php 的类定义
function __autoload($class) {
include &#39;classes/&#39; . $class . &#39;.class.php&#39;;
}
// PHP 5.3 后直接使用匿名函数注册
$throw = true; // 注册出错时是否抛出异常
$prepend = false; // 是否将当前注册函数添加到队列头
spl_autoload_register(function ($class) {
include &#39;classes/&#39; . $class . &#39;.class.php&#39;;
}, $throw, $prepend);</pre></pre>
composer によって生成された自動ロード ファイル
で次のことがわかります: <pre class="brush:php;toolbar:false">class ComposerAutoloaderInit8b41a
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
// 加载当前目录下文件
require __DIR__ . '/ClassLoader.php';
}
}
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
// 注册自己的加载器
spl_autoload_register(array('ComposerAutoloaderInit8b41a6', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit8b41a6a', 'loadClassLoader'));
...
}
...
}</pre>
ここでは、特に Laravel がどのように自動的に実行するかについてのみ説明します。全体として読み込み中 はい、次の記事で詳しく説明します。
Reflection
PHP マニュアルを参照してください。これは、実行時にオブジェクトの完全な情報を取得すると単純に理解できます。リフレクションには 5 つのクラスがあります:
ReflectionClass // 解析类名 ReflectionProperty // 获取和设置类属性的信息(属性名和值、注释、访问权限) ReflectionMethod // 获取和设置类函数的信息(函数名、注释、访问权限)、执行函数等 ReflectionParameter // 获取函数的参数信息 ReflectionFunction // 获取函数信息
たとえば、
ReflectionClass の使用: <pre class="brush:php;toolbar:false"><?php class User
{
public $name;
public $age;
public function __construct($name = &#39;Laruence&#39;, $age = 35) {
$this->name = $name;
$this->age = $age;
}
public function intro() {
echo '[name]: ' . $this->name . PHP_EOL;
echo '[age]: ' . $this->age . PHP_EOL;
}
}
reflect('User');
// ReflectionClass 反射类使用示例
function reflect($class) {
try {
$ref = new ReflectionClass($class);
// 检查是否可实例化
// interface、abstract class、 __construct() 为 private 的类均不可实例化
if (!$ref->isInstantiable()) {
echo "[can't instantiable]: ${class}\n";
}
// 输出属性列表
// 还能获取方法列表、静态常量等信息,具体参考手册
foreach ($ref->getProperties() as $attr) {
echo $attr->getName() . PHP_EOL;
}
// 直接调用类中的方法,个人认为这是反射最好用的地方
$obj = $ref->newInstanceArgs();
$obj->intro();
} catch (ReflectionException $e) {
// try catch 机制真的不优雅
// 相比之下 Golang 的错误处理虽然繁琐,但很简洁
echo '[reflection exception: ]' . $e->getMessage();
}
}</pre>
Run:
$ php reflect.php name age [name]: Laruence [age]: 35
他の 4 つのリフレクション クラスの場合マニュアルのデモを参照してください。
後期静的バインディング
最初に PHP マニュアルを参照して例を見てください:
<?php class Base { // 后期绑定不局限于 static 方法 public static function call() { echo '[called]: ' . __CLASS__ . PHP_EOL; } public static function test() { self::call(); // self 取值为 Base 直接调用本类中的函数 static::call(); // static 取值为 Child 调用者 } } class Child extends Base { public static function call() { echo '[called]: ' . __CLASS__ . PHP_EOL; } } Child::test();
出力:
$ php late_static_bind.php [called]: Base [called]: Child
オブジェクトがインスタンス化されるとき、
self:: はそれが定義されているクラスをインスタンス化し、static::
はそれを呼び出すクラスをインスタンス化します。 trait
基本的な使い方
PHPマニュアル参照 PHPは単一継承ですが、5.4以降では「クラス」を水平結合することで実現できるようになりました。多重継承とは、実際には、繰り返される関数をトライアットに分割して異なるファイルに配置し、必要に応じて use キーワードを使用して導入および結合することです。継承は、Golang の構造体詰め込みの組み合わせと同様に実装できます。例:
<?php class DemoLogger { public function log($message, $level) { echo "[message]: $message", PHP_EOL; echo "[level]: $level", PHP_EOL; } } trait Loggable { protected $logger; public function setLogger($logger) { $this->logger = $logger; } public function log($message, $level) { $this->logger->log($message, $level); } } class Foo { // 直接引入 Loggable 的代码片段 use Loggable; } $foo = new Foo; $foo->setLogger(new DemoLogger); $foo->log('trait works', 1);
実行:
$ php trait.php [message]: trait works [level]: 1
その他の参照: PHP Trait について理解していること
重要なプロパティ
Priority
現在のクラスの関数はトレイトの同じ名前の関数を上書きし、トレイトは親クラスの同じ名前の関数を上書きします (
use trait は、現在のクラスがトレイトを直接上書きするのと同等です) trait function Conflict
複数のトレイトの同時導入は
, で区切ることができます、つまり多重継承。 <p>多个 trait 有同名函数时,引入将发生命名冲突,使用 <code>insteadof
来指明使用哪个 trait 的函数。
重命名与访问控制
使用 as
关键字可以重命名的 trait 中引入的函数,还可以修改其访问权限。
其他
trait 类似于类,可以定义属性、方法、抽象方法、静态方法和静态属性。
下边的苹果、微软和 Linux 的小栗子来说明:
<?php trait Apple { public function getCEO() { echo '[Apple CEO]: Tim Cook', PHP_EOL; } public function getMarketValue() { echo '[Apple Market Value]: 953 billion', PHP_EOL; } } trait MicroSoft { public function getCEO() { echo '[MicroSoft CEO]: Satya Nadella', PHP_EOL; } public function getMarketValue() { echo '[MicroSoft Market Value]: 780 billion', PHP_EOL; } abstract public function MadeGreatOS(); static public function staticFunc() { echo '[MicroSoft Static Function]', PHP_EOL; } public function staticValue() { static $v; $v++; echo '[MicroSoft Static Value]: ' . $v, PHP_EOL; } } // Apple 最终登顶,成为第一家市值超万亿美元的企业 trait Top { // 处理引入的 trait 之间的冲突 use Apple, MicroSoft { Apple::getCEO insteadof MicroSoft; Apple::getMarketValue insteadof MicroSoft; } } class Linux { use Top { // as 关键字可以重命名函数、修改权限控制 getCEO as private noCEO; } // 引入后必须实现抽象方法 public function MadeGreatOS() { echo '[Linux Already Made]', PHP_EOL; } public function getMarketValue() { echo '[Linux Market Value]: Infinity', PHP_EOL; } } $linux = new Linux(); // 和 extends 继承一样 // 当前类中的同名函数也会覆盖 trait 中的函数 $linux->getMarketValue(); // trait 中可以定义静态方法 $linux::staticFunc(); // 在 trait Top 中已解决过冲突,输出库克 $linux->getCEO(); // $linux->noCEO(); // Uncaught Error: Call to private method Linux::noCEO() // trait 中可以定义静态变量 $linux->staticValue(); $linux->staticValue();
运行:
$ php trait.php [Linux Market Value]: Infinity [MicroSoft Static Function] [Apple CEO]: Tim Cook [MicroSoft Static Value]: 1 [MicroSoft Static Value]: 2
总结
本节简要提及了命名空间、文件自动加载、反射机制与 trait 等,Laravel 正是恰如其分的利用了这些新特性,才实现了组件化开发、服务加载等优雅的特性。