感覺好長時間沒寫東西了,一方面主要是自己的角色發生了變化,每天要面對各種各樣的事情和突發事件,不能再有一個完整的長時間讓自己靜下來寫程式碼,或者寫文章。
另一方面現在公司技術棧不再停留在只有 Laravel + VUE 了,我們還有小程式、APP 等開發,所以我關注的東西也就多了。
接下來我還是會繼續持續「高產」,把寫技術文章當作一個習慣,堅持下去。
好了,廢話不多說,今天來說一說「Eloquent: 修改器
」。
一直想好好研究下 Eloquent。但苦於 Eloquent 有太多可研究的,無法找到一個切入點。前兩天看一同事好像對這個「Eloquent: 修改器
」瞭解不多,所以今天就拿它作為入口,扒一扒其實現原始碼。
首先還是拿一個 Demo 為例:
Demo
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;
class Baby extends Model
{
protected $table = 'baby';
protected $appends = ['age'];
public function getAgeAttribute()
{
$date = new Carbon($this->birthday);
return Carbon::now()->diffInYears($date);
}
}
複製程式碼
這個程式碼比較簡單,就是通過已有屬性 birthday
,計算 Baby 幾歲了,得到 age
屬性。
前端就可以直接拿到結果:
return $baby->age;
複製程式碼
同樣的,還有 setXxxAttribute
方法來定義一個修改器。
原始碼
讀程式碼還是從使用入手,如上通過 $baby->age
呼叫 age
屬性,這個屬性沒在類中定義,所以只能通過 PHP 的魔術方法 __get()
呼叫了。
我們看看 Model
類的 __get()
方法:
/**
* Dynamically retrieve attributes on the model.
*
* @param string $key
* @return mixed
*/
public function __get($key)
{
return $this->getAttribute($key);
}
複製程式碼
好了,我們開始解讀原始碼了:
/**
* Get an attribute from the model.
*
* @param string $key
* @return mixed
*/
public function getAttribute($key)
{
if (! $key) {
return;
}
// If the attribute exists in the attribute array or has a "get" mutator we will
// get the attribute's value. Otherwise, we will proceed as if the developers
// are asking for a relationship's value. This covers both types of values.
if (array_key_exists($key, $this->attributes) ||
$this->hasGetMutator($key)) {
return $this->getAttributeValue($key);
}
...
}
複製程式碼
重點自然就在第二個 if
上,主要判斷 attributes
陣列中是否包含該屬性,如果沒有,則會執行函式 $this->hasGetMutator($key)
:
/**
* Determine if a get mutator exists for an attribute.
*
* @param string $key
* @return bool
*/
public function hasGetMutator($key)
{
return method_exists($this, 'get'.Str::studly($key).'Attribute');
}
複製程式碼
這就對上了我們的 Demo
中自定義的函式 getAgeAttribute()
,也就返回 true
了。
接下來就是執行函式 $this->getAttributeValue($key)
,進而執行函式:return $this->mutateAttribute($key, $value);
/**
* Get the value of an attribute using its mutator.
*
* @param string $key
* @param mixed $value
* @return mixed
*/
protected function mutateAttribute($key, $value)
{
return $this->{'get'.Str::studly($key).'Attribute'}($value);
}
複製程式碼
好了,到此我們基本就知道了獲取自定義 Attribute
的流程了。
相信解析 set XxxAttribute
也是很簡單的。
總結
好長時間沒寫東西了,先從最簡單的入手,練練手。解析 Eloquent
需要費很多腦細胞,接下來的一段時間我會圍繞著這個主題好好研究下去,儘可能的全部解讀一遍::
.
|____Capsule
| |____Manager.php
|____composer.json
|____Concerns
| |____BuildsQueries.php
| |____ManagesTransactions.php
|____Connection.php
|____ConnectionInterface.php
|____ConnectionResolver.php
|____ConnectionResolverInterface.php
|____Connectors
| |____ConnectionFactory.php
| |____Connector.php
| |____ConnectorInterface.php
| |____MySqlConnector.php
| |____PostgresConnector.php
| |____SQLiteConnector.php
| |____SqlServerConnector.php
|____Console
| |____Factories
| | |____FactoryMakeCommand.php
| | |____stubs
| | | |____factory.stub
| |____Migrations
| | |____BaseCommand.php
| | |____FreshCommand.php
| | |____InstallCommand.php
| | |____MigrateCommand.php
| | |____MigrateMakeCommand.php
| | |____RefreshCommand.php
| | |____ResetCommand.php
| | |____RollbackCommand.php
| | |____StatusCommand.php
| |____Seeds
| | |____SeedCommand.php
| | |____SeederMakeCommand.php
| | |____stubs
| | | |____seeder.stub
|____DatabaseManager.php
|____DatabaseServiceProvider.php
|____DetectsDeadlocks.php
|____DetectsLostConnections.php
|____Eloquent
| |____Builder.php
| |____Collection.php
| |____Concerns
| | |____GuardsAttributes.php
| | |____HasAttributes.php
| | |____HasEvents.php
| | |____HasGlobalScopes.php
| | |____HasRelationships.php
| | |____HasTimestamps.php
| | |____HidesAttributes.php
| | |____QueriesRelationships.php
| |____Factory.php
| |____FactoryBuilder.php
| |____JsonEncodingException.php
| |____MassAssignmentException.php
| |____Model.php
| |____ModelNotFoundException.php
| |____QueueEntityResolver.php
| |____RelationNotFoundException.php
| |____Relations
| | |____BelongsTo.php
| | |____BelongsToMany.php
| | |____Concerns
| | | |____InteractsWithPivotTable.php
| | | |____SupportsDefaultModels.php
| | |____HasMany.php
| | |____HasManyThrough.php
| | |____HasOne.php
| | |____HasOneOrMany.php
| | |____MorphMany.php
| | |____MorphOne.php
| | |____MorphOneOrMany.php
| | |____MorphPivot.php
| | |____MorphTo.php
| | |____MorphToMany.php
| | |____Pivot.php
| | |____Relation.php
| |____Scope.php
| |____SoftDeletes.php
| |____SoftDeletingScope.php
|____Events
| |____ConnectionEvent.php
| |____QueryExecuted.php
| |____StatementPrepared.php
| |____TransactionBeginning.php
| |____TransactionCommitted.php
| |____TransactionRolledBack.php
|____Grammar.php
|____Migrations
| |____DatabaseMigrationRepository.php
| |____Migration.php
| |____MigrationCreator.php
| |____MigrationRepositoryInterface.php
| |____Migrator.php
| |____stubs
| | |____blank.stub
| | |____create.stub
| | |____update.stub
|____MigrationServiceProvider.php
|____MySqlConnection.php
|____PostgresConnection.php
|____Query
| |____Builder.php
| |____Expression.php
| |____Grammars
| | |____Grammar.php
| | |____MySqlGrammar.php
| | |____PostgresGrammar.php
| | |____SQLiteGrammar.php
| | |____SqlServerGrammar.php
| |____JoinClause.php
| |____JsonExpression.php
| |____Processors
| | |____MySqlProcessor.php
| | |____PostgresProcessor.php
| | |____Processor.php
| | |____SQLiteProcessor.php
| | |____SqlServerProcessor.php
|____QueryException.php
|____README.md
|____Schema
| |____Blueprint.php
| |____Builder.php
| |____Grammars
| | |____ChangeColumn.php
| | |____Grammar.php
| | |____MySqlGrammar.php
| | |____PostgresGrammar.php
| | |____RenameColumn.php
| | |____SQLiteGrammar.php
| | |____SqlServerGrammar.php
| |____MySqlBuilder.php
| |____PostgresBuilder.php
| |____SQLiteBuilder.php
| |____SqlServerBuilder.php
|____Seeder.php
複製程式碼
參考
- Eloquent: 修改器 laravel-china.org/docs/larave…
- __get()使用說明 php.net/manual/zh/l…
未完待續