ファイルの読み込み---プロジェクトを理解するための最初のステップ---プロジェクト
私が最初に PHP を書き始めたとき、私はいつもこの問題について心配していました: ここで作成した新しいクラスを対応するクラスにロードできるか? ?結局のところ、致命的エラーは、実行するとすぐに報告されます。** ファイルが見つからない、クラスをインスタンス化できないなどです。これは非常に「低レベル」のエラーであり、他の人が読むのではないかと心配しています。それは冗談です。そのため、新しいタスクを引き受けるたびに、その読み込みプロセスを理解したいと考えています (以前は HTML タグとスタイルをいくつかしか知らなかったので、それが Web 開発としてカウントされるかどうかはわかりません)。それを読んで、まだこれを読む時間があると言うので、彼はロジックを急いで書きます。これを実行してください...お姉さん、もちろん、あなたはそれを確信していますD:、しかし後で私は、プロセスがほとんど終わっていることがわかりました同じ。
C++/Java などの IDE で開発する場合、通常は新しいプロジェクトを作成し、IDE を介して指定されたディレクトリに新しいファイルを追加し、それを #include/Import します。PHP ではこのステップがより手続き的になっており、ファイル 読み込みプロセスは基本的に、このプロジェクト (フレームワークまたは自己構築プロジェクト) のディレクトリ構造とファイル分類を決定します。
フレームワークであっても、自作プロジェクトであっても、エントリーファイルが存在する必要があります。このとき、設定ファイルや共通メソッドなど、いくつかの基本情報を事前にロードする必要があります。基本的な方法は手動でロードすることです。次の 4 つの方法のいずれかを使用して、単一のファイルを直接作成します:
include、require、include_once、require_once
リーリークラス ファイルのロードに関しては、少数のファイルが直接ロードされます。たとえば、一般的なメソッドは後で使用されるメソッド (エラー出力、curl など) が多いため、クラス Utilities に静的メソッドとして記述されます。リクエスト、ランダムな文字列生成。..) なので、クラスでカプセル化され、通常は設定ファイルのロード時にロードされます
include('Utilities.php');
より一般的な状況は、クラスの動的ロードです。まずロードメソッドについては話さないで、クラスとインスタンスがいつ使用されるかを見てみましょう:
1. 最も明白なのは、$obj = new A; そのバリアント $obj = $className; です。
2. クラスの静的メソッド、静的変数、定数、つまり Utilities::httpRequest()、Utilities::$instance、Utilities::HOST を呼び出す。3. PHP 関数でコールバック関数を使用する場合、最も一般的なのは call_user_func_array() (call_user_func) です。他にも配列内の array_walk や array_map など、コールバック関数をパラメータとして使用する必要があります。 。
コールバック関数は非常に柔軟であり、単純な関数だけでなく、静的クラスメソッドを含むオブジェクトメソッドにすることもできます。オブジェクト メソッドまたは静的メソッドを使用できるため、この時点で対応するクラス ファイルを読み込む必要があります。 PHP 5.3 以降では、js のような匿名関数を使用してコールバック関数を実装することもできます。
リーリー厳密に言えば、上記の例の call_user_func_array はすでにオブジェクトをインスタンス化していますが、このような使い方があり、クラスの静的メソッドを使用することもできます。
最初に理解することは、なぜ動的読み込みが必要なのかということです。 PHP はスクリプト言語です。たとえば、localhost/index として直接アクセスすると、ルート ディレクトリにindex.php ファイルが存在します。 php にあるすべてのリソースにアクセスできます。index.php で共通のクラス A が定義されている場合、A のオブジェクトがスクリプト内でインスタンス化されると、プログラムは次のように反応します。 A の定義を作成し、それを直接インスタンス化できます (他のファイルをロードする必要はありません)。クラスB、C、Dなどのクラスがたくさんある場合、それらをすべてindex.phpに書いて別のファイルに書いてインクルードすると当然動作しません(インクルードはすでに読み込み作業を行っています)。プログラムでは機能しません。これも「表示」されます。
しかし、システムの機能が増えるにつれてクラスの数も増え、各クラスの機能も異なります。データベース操作を直接定義してデータベースデータを読み取るもの、スクリプトにアクセスするときに実行するメソッドを制御するもの、などです。表示されるページのうち、参照するサードパーティのコア ライブラリは、すべてのファイルをディレクトリに配置すると、インクルードによって直接ロードできますが、これらのファイルの配置が乱雑で見つけにくいように見えます。維持コストが削減されます。さて、ルート ディレクトリにさらにいくつかのディレクトリを作成しましょう。ディレクトリ A は、データベースを処理するスクリプトの保存専用です。ディレクトリ C は、プログラム開始時のエントリ制御方法を制御します。スクリプト、ディレクトリ D はブラウザに表示されるページです...
于是MVC架构慢慢就演化出来了,我们不能再像以前那样直接include,脚本都放在特定的目录下,如Controller目录下存放的是各种控制器,加载控制器时,我们得这样include('root/Controller/indexController.php'),每次都在文件前面弄一大串的include不仅看着头疼,简直让人累觉不爱。既然有了获取当前文件路径和类名的现成方法,为何不将类名与文件名对应起来,而只要是控制器类的脚本就全放在根目录的Controller子目录下边,就可以写一个方法,只要是控制器类,在这个方法中运行include(ROOT.'Controller/'.$className.'.php');这一句,ROOT为根目录常量,$className为传入的类名,只要是模型类,就这样include(ROOT.'Model/'.$className.'.php');,全凭这个函数来动态控制到哪个目录里边去找,这个project可能就是这样的:
无形中,就建立起了类名和文件名的对应规则,文件和所在的目录的对应规则,该project下有哪些这样的目录和文件呢?啊原来是放控制器的Controller、放配置信息的Config等等,再次于无形中得知了这个project的结构,而上面说的,利用函数根据一定条件(传入参数)可知自动到哪个目录下去加载该文件,而不是一个个写死的include,就是所谓的文件的动态加载了。
因此,当你要新建一个**类文件时,也就知道,哦在这个project中,我应该放在这个目录下,文件的命名应该与类名相同,这样就一定能加载到了~~~接下来就是写业务逻辑的一个“愉快的过程”。
知道什么时候会动态加载及为什么要动态加载后,接下来就是来实现了,也就是上面说到的利用函数来加载某个文件,就是要写好这个“函数”来实现这个过程。常用的有三种方式:
1. __autoload
我第一次学的时候就是用的就是这个,魔术函数,只要定义了php程序就会在要用到一个类时自动调用它进行文件动态加载,一样,既然它是个函数,就要让程序对__autoload的定义可见,不然从哪儿调用它呢?一般来说,作为后边程序大部分地方要用到的方法,我们都会放在一个单独的文件中,在程序的入口处加载进来,一个project总得有几个文件是手动include的,完全可以在开头单独include进来,或者放在配置信息中,加载配置信息时就加载进来了。它的原型:
void __autoload ( string $class )
参数当前加载的类名名称(注意如果有命名空间,则包含命名空间前缀),下面是一个针对上面的图片结构的简单示例:
<span>//</span><span> file: autoload.php // ROOT为已经定义的根目录常量</span> <span>function</span> __autoload(<span>$className</span><span>){ </span><span>try</span><span>{ </span><span>if</span>(<span>file_exists</span>(ROOT.'Controller/'.<span>$className</span>.'.php')){<span>//</span><span> 检查Controller</span> <span>include</span>(ROOT.'Controller/'.<span>$className</span>.'.php'<span>); } </span><span>else</span> <span>if</span>(<span>file_exists</span>(ROOT.'Model/'.<span>$className</span>.'.php')){<span>//</span><span> 检查Model</span> <span>include</span>(ROOT.'Model/'.<span>$className</span>.'.php'<span>); } </span><span>else</span> <span>if</span>(<span>file_exists</span>(ROOT.'Lib/'.<span>$className</span>.'.php')){<span>//</span><span> 检查Lib</span> <span>include</span>(ROOT.'Lib/'.<span>$className</span>.'.php'<span>); } </span><span>else</span>{ <span>//</span><span> 找不到该文件</span> <span>throw</span> <span>new</span> <span>Exception</span>("ERROR: can't find file {<span>$className</span>}.php"<span>); } } </span><span>catch</span>(<span>Exception</span> <span>$e</span><span>){ </span><span>echo</span> <span>$e</span>.<span>getMessage(); </span><span>exit</span><span>; } }</span>
2. spl_autoload_register
__autoload实际上也差不多了,但它是php定义的,如果现在有个东西写了并调用之后,就告诉程序说,我不用__autoload来加载文件了,我已经定义了一个专门加载文件的方法(比如名称是loadClass),以后需要加载一个类文件时,你就用它吧。spl_autoload_register就是这样一个能告诉程序这样去做的方法,而且自定义加载方法将会更灵活,可以指定多个加载函数,spl_autoload_register函数会将这些函数放在一个队列中,并激活它们,在调用时逐个激活:“If there must be multiple autoload functions, spl_autoload_register() allows for this. It effectively creates a queue of autoload functions, and runs through each of them in the order they are defined. ”,php.net上(http://php.net/manual/en/function.spl-autoload-register.php)也确实如此解释,spl_autoload_unregister则是从加载函数队列中注销。
另外spl_autoload_functions()函数,可以获取我们注册了哪些函数;spl_autoload_call($class)函数,尝试调用所有已注册的加载函数来加载$class的类文件。
对于spl_autoload_register的解释,我的理解是,如果用spl_autoload_register注册了n个函数在加载队列中,因为它自动激活它们嘛,现在我要实例化一个类,在第1个加载函数中加载失败了,然后尝试第2个函数,第二个失败则尝试第3个,''',直到第n个函数走完,若还没加载成功,就报错,只要中间一个加载成功就成功了,but事实好像有点出入。
还是用上一个图片中的目录结构,
1、在Controller目下创建indexController.php文件,包含类indexController;
2、在Model目录下创建userModel.php文件,包含类userModel;
3、首页写个类加载脚本Autoload.php,代码如下:
<span>//</span><span> file: Autoload.php</span> <span>define</span>('DS',<span> DIRECTORY_SEPARATOR); </span><span>define</span>('ROOT', <span>rtrim</span>(<span>dirname</span>(<span>__FILE__</span>), '/\\').<span>DS); </span><span>class</span><span> Autoload{ </span><span>public</span> <span>static</span> <span>function</span> autoloadRegister(<span>$loadFunc</span> = 'Autoload::loadControllerClass', <span>$enable</span> = <span>true</span><span>){ </span><span>return</span> <span>$enable</span> ? spl_autoload_register(<span>$loadFunc</span>) : spl_autoload_unregister(<span>$loadFunc</span><span>); } </span><span>//</span><span> 加载控制器类</span> <span>public</span> <span>static</span> <span>function</span> loadControllerClass(<span>$className</span><span>){ </span><span>if</span>(<span>file_exists</span>(ROOT.'Controller'.DS.<span>$className</span>.'.php')){<span>//</span><span> 检查Controller</span> <span>include</span>(ROOT.'Controller'.DS.<span>$className</span>.'.php'<span>); </span><span>echo</span> ROOT.'Controller'.DS.<span>$className</span>.'.php'.'<br/>'<span>; } </span><span>else</span><span>{ </span><span>echo</span> "ERROR: can't find file {<span>$className</span>}.php in ".ROOT."Controller"<span>; </span><span>exit</span><span>; } } </span><span>//</span><span> 加载模型类</span> <span>public</span> <span>static</span> <span>function</span> loadModelClass(<span>$className</span><span>){ </span><span>if</span>(<span>file_exists</span>(ROOT.'Model'.DS.<span>$className</span>.'.php')){<span>//</span><span> 检查Model</span> <span>include</span>(ROOT.'Model'.DS.<span>$className</span>.'.php'<span>); </span><span>echo</span> ROOT.'Model'.DS.<span>$className</span>.'.php'.'<br/>'<span>; } </span><span>else</span><span>{ </span><span>echo</span> "ERROR: can't find file {<span>$className</span>}.php in ".ROOT."Model"<span>; </span><span>exit</span><span>; } } }</span>
4、测试脚本,测试类是否能加载
<span>//</span><span> 注册两个加载函数</span> Autoload::autoloadRegister('Autoload::loadControllerClass'<span>); Autoload</span>::autoloadRegister('Autoload::loadModelClass'<span>);</span><span> // 查看总共注册了哪些加载函数</span> <span>echo</span> 'register functions=> <pre class="brush:php;toolbar:false">'<span>; </span><span>print_r</span><span>(spl_autoload_functions()); </span><span>//</span><span> 分别实例化一个Controller类和Model类</span> <span>$indexCon</span> = <span>new</span><span> indexController; </span><span>$userMod</span> = <span>new</span> userModel;
结果是这样
这不科学啊,spl_autoload_functions数组显示两个函数都注册了,但是当实例化userModel类时它还是跑到Controller目录中去找,两个类的实例化调用的自动加载方法都是Autoload::loadControllerClass,所以userModel类文件加载报错......注意到spl_autoload_register方法的第三个参数, 是添加一个加载函数时放在栈中的位置,于是我另写一个类似的类otherLoad,只是为了将loadModelClass方法放到队列首部:
<span>class</span><span> otherLoad{ </span><span>public</span> <span>static</span> <span>function</span> autoloadRegister(<span>$loadFunc</span> = 'otherLoad::loadModelClass', <span>$enable</span> = <span>true</span><span>){ </span><span>//</span><span> 默认将loadModelClass放在队首</span> <span>return</span> <span>$enable</span> ? spl_autoload_register(<span>$loadFunc</span>, <span>true</span>, <span>true</span>) : spl_autoload_unregister(<span>$loadFunc</span><span>); } </span><span>//</span><span> 加载模型类</span> <span>public</span> <span>static</span> <span>function</span> loadModelClass(<span>$className</span><span>){ </span><span>if</span>(<span>file_exists</span>(ROOT.'Model'.DS.<span>$className</span>.'.php')){<span>//</span><span> 检查Model</span> <span>include</span>(ROOT.'Model'.DS.<span>$className</span>.'.php'<span>); </span><span>echo</span> ROOT.'Model'.DS.<span>$className</span>.'.php'.'<br/>'<span>; } </span><span>else</span><span>{ </span><span>echo</span> "ERROR: can't find file {<span>$className</span>}.php in ".ROOT."Model"<span>; </span><span>exit</span><span>; } } } </span>
测试是这样
<span>//</span><span> 注册三个加载函数</span> Autoload::autoloadRegister('Autoload::loadControllerClass'<span>); Autoload</span>::autoloadRegister('Autoload::loadModelClass'<span>); otherLoad</span>::autoloadRegister('otherLoad::loadModelClass'<span>); </span><span>//</span><span> 查看总共注册了哪些加载函数</span> <span>echo</span> 'register functions=> <pre class="brush:php;toolbar:false">'<span>; </span><span>print_r</span><span>(spl_autoload_functions()); </span><span>//</span><span> 分别实例化一个Controller类和Model类</span> <span>$indexCon</span> = <span>new</span><span> indexController; </span><span>$userMod</span> = <span>new</span> userModel;
这次的结果是这样:
可以看到,这次是在加载indexController类时不成功,因为它只调用了loadModelClass方法,再看看spl_autoload_functions返回的数组,otherLoad类的loadModelClass方法在最前面,难道说,只有在加载函数队列最前面的函数才被用于自动加载,其他无效?这是什么状况?
使用spl_autoload_call('indexController')来“尝试调用所有已注册的函数来装载请求类”,还是报这个错。
翻了下别人的文章,包括github上的博客,也就是列举了下手册上说的“可以一次注册多个加载函数 bala bala......”,难道没有人试过,还是我的理解有问题>3<...>
关于spl_autoload_register还有几个有意思的地方:
1、 一个函数只会加载到函数队列中一次,重复加载也是如此;
2、 spl_autoload_register如果不指定加载函数(第一个参数),则默认使用加载函数spl_autoload(功能类似于__autoload,是它的默认实现形式)
3、 spl_autoload_register指定了__autoload为加载函数,则一定要实现__autoload;
4、 同时实现了spl_autoload_register和__autoload,优先使用spl_autoload_register注册的加载函数。
以上几种情况几乎都可从php.net的note中找到测试例子,老外写得挺有意思,可供参考。上面第2点还需要注意,比如现在在根目录创建一个目录,使用默认函数来加载:
<span>//</span><span> 设置加载文件的扩展名,将只加载*.php的文件</span> spl_autoload_extensions('.php'<span>); </span><span>//</span><span> 默认使用spl_autoload加载文件,只能加载当前目录下文件:小写类名.php</span> <span> spl_autoload_register(); </span><span>//</span><span> 测试 // $obj = new A;</span>
spl_autoload_extensions设置加载时只认哪些扩展类型的文件,默认是.php或者.inc文件,这里设置成.php,然后就是调用注册函数。在根目录下创建一个A.php文件,新建一个类A,加载成功,再将文件名改成a.php,照样加载成功。需要留意spl_autoload默认将类名转小写,但是A.php照样加载成功,因为Windows的文件是大小写不敏感的(在同一目录下创建一个d.txt,再创建D.txt会认为是同一个文件),对于Mac OS X也是这样,但Linux就是大小写敏感了,测试时要注意这点。
也不是全要自动加载,如CI,它将加载文件封装为一个核心类CI_Loader,程序启动时先include必要的脚本(其他要用的核心类),然后再等需要使用时,CI_Loader实例作为当前控制器类或模型类等的一个属性成员,通过调用它的方法来include各种model(模型)、view(视图)、database(数据库对象)、helper(辅助函数)等等。
動的読み込みを使用するかどうかに関係なく、ファイルがカテゴリに配置され、特定のルールに従ってファイルに名前が付けられることを確認する必要があります。これは、堅牢で拡張性が高く、使いやすいものにするために必須です。プロジェクトを作成し、コードを記述するのにも便利です。もちろん、ロードされるファイルの数や占有メモリの量は人によって異なり、フレームワークを判断する基準にもなります。読み込み方法を理解してフレームワークの構造に慣れるのは簡単ではないでしょうか =_=...

PHPでは、特性は方法が必要な状況に適していますが、継承には適していません。 1)特性により、クラスの多重化方法が複数の継承の複雑さを回避できます。 2)特性を使用する場合、メソッドの競合に注意を払う必要があります。メソッドの競合は、代替およびキーワードとして解決できます。 3)パフォーマンスを最適化し、コードメンテナビリティを改善するために、特性の過剰使用を避け、その単一の責任を維持する必要があります。

依存関係噴射コンテナ(DIC)は、PHPプロジェクトで使用するオブジェクト依存関係を管理および提供するツールです。 DICの主な利点には、次のものが含まれます。1。デカップリング、コンポーネントの独立したもの、およびコードの保守とテストが簡単です。 2。柔軟性、依存関係を交換または変更しやすい。 3.テスト可能性、単体テストのために模擬オブジェクトを注入するのに便利です。

SplfixedArrayは、PHPの固定サイズの配列であり、高性能と低いメモリの使用が必要なシナリオに適しています。 1)動的調整によって引き起こされるオーバーヘッドを回避するために、作成時にサイズを指定する必要があります。 2)C言語アレイに基づいて、メモリと高速アクセス速度を直接動作させます。 3)大規模なデータ処理とメモリに敏感な環境に適していますが、サイズが固定されているため、注意して使用する必要があります。

PHPは、$ \ _ファイル変数を介してファイルのアップロードを処理します。セキュリティを確保するための方法には次のものが含まれます。1。アップロードエラー、2。ファイルの種類とサイズを確認する、3。ファイル上書きを防ぐ、4。ファイルを永続的なストレージの場所に移動します。

JavaScriptでは、nullcoalescingoperator(??)およびnullcoalescingsignmentoperator(?? =)を使用できます。 1.??最初の非潜水金または非未定されたオペランドを返します。 2.??これらの演算子は、コードロジックを簡素化し、読みやすさとパフォーマンスを向上させます。

XSS攻撃を防ぎ、リソースのロードを制限し、ウェブサイトのセキュリティを改善できるため、CSPは重要です。 1.CSPはHTTP応答ヘッダーの一部であり、厳格なポリシーを通じて悪意のある行動を制限します。 2。基本的な使用法は、同じ起源からのロードリソースのみを許可することです。 3.高度な使用法は、特定のドメイン名がスクリプトやスタイルをロードできるようにするなど、より微調整された戦略を設定できます。 4。CSPポリシーをデバッグおよび最適化するには、コンテンツセキュリティポリシーレポートのみのヘッダーを使用します。

HTTPリクエストメソッドには、それぞれリソースを取得、送信、更新、削除するために使用されるGET、POST、PUT、および削除が含まれます。 1. GETメソッドは、リソースを取得するために使用され、読み取り操作に適しています。 2. POSTメソッドはデータの送信に使用され、新しいリソースを作成するためによく使用されます。 3. PUTメソッドは、リソースの更新に使用され、完全な更新に適しています。 4.削除メソッドは、リソースの削除に使用され、削除操作に適しています。

HTTPSは、HTTPに基づいてセキュリティレイヤーを追加するプロトコルであり、主に暗号化されたデータを介してユーザーのプライバシーとデータセキュリティを保護します。その作業原則には、TLSの握手、証明書の確認、暗号化された通信が含まれます。 HTTPSを実装する場合、証明書管理、パフォーマンスへの影響、および混合コンテンツの問題に注意を払う必要があります。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

SecLists
SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

メモ帳++7.3.1
使いやすく無料のコードエディター

ドリームウィーバー CS6
ビジュアル Web 開発ツール

AtomエディタMac版ダウンロード
最も人気のあるオープンソースエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ホットトピック



