Mình chắc bạn đang thắc mắc về vụ mà người ta hay gọi là dynamic import.
Mình không rành PHP, nhưng mình cũng từng là dân Compiler nên biết chút về vụ này.
Đa số việc importing thuộc dạng static import, các câu lệnh import thường để ở đầu file.
// Java
import java.util.List;
import java.util.ArrayList;
public class Foo { }
use Zend\Mvc\Controller\AbstractController;
class IndexController extends AbstractController { }
Thường khi dùng static import thì người ta chỉ import tên class, tên constant, tên biến mà không cần biết class, constant hay biến thuộc file nào. Đặc điểm chung của mấy lệnh import trong các ngôn ngữ trên (Java, PHP, …) là không có tên file.
Static import hồi cũ là sử dụng tên file, thường thấy nhất là ngôn ngữ C, C++. Nó sẽ tìm tên file rồi copy nguyên xi file gốc (stdio.h
, iostream.h
,…) vào luôn.
#include <stdio.h>
#include <math.h>
#include <iostream>
#include <vector>
Tuy nhiên, đối với các scripting language, điển hình là JavaScript, vẫn sử dụng các import bằng tên file, nhưng có cách để tránh việc copy-paste như C.
// CommonJS
var express = require('express');
var Todo = require('./models/Todo');
// ES6 Module
import { Component } from '@angular/core'
import { AppComponent } from './root/AppComponent'
Cách để tránh copy-paste là JavaScript chia việc thực thi thành 2 giai đoạn: compile time và runtime.
Ở giai đoạn compile time, JS đọc file từ trên xuống dưới, lọc ra các câu lệnh require
và import
. Với mỗi lệnh static import, nó thực hiện đệ quy bước compile time trên file mới. Đọc import xong, nó chạy tất cả các lệnh thuộc global scope (và các lệnh thuộc local scope được gọi từ global scope). Khi chạy hết là hoàn tất bước compile time.
Trong thời gian runtime, nếu 1 file khác gọi 1 đoạn function trong file (trên) thì JS mới thực thi các câu lệnh trong local scope (bao gồm không được gọi từ global scope ở compile time).
Tóm lại, static import thì thường người ta chỉ cần import tên class, tên biến. Nếu gặp cách cũ thì có thể import tên file, nhưng cải tiến bằng cách chia thành 2 giai đoạn thực thi: compile time và runtime.
Dạng thứ hai của import là dynamic import. Đặc điểm chung của dynamic import là chỉ xảy ra ở runtime. Nếu gặp lệnh import thì mới bắt đầu import. Nếu lệnh được thực thi nhiều lần thì import bấy nhiêu lần.
Dynamic import thường gặp ở trong REPL. Nếu mở Terminal, gõ php
, node
, python
thì chính là REPL. Khi bạn gõ mấy câu lệnh theo cú pháp static import thì thực chất nó gọi theo dynamic import luôn đó. Do đó, dạng import này thì ai cũng xài rồi nhưng lại không biết.
Một kiểu static import khác nhìn hao hao giống dynamic import là static import bị giới hạn scope, điển hình là Scala
class Foo1 {
import Bar1
def baz = {
import Baz1
}
}
class Foo2 {
import Bar2
}
Bar1
bị giới hạn trong Foo1
, Bar2
bị giới hạn trong Foo2
. Foo2
không gọi được Bar1
, Foo1
không gọi được Bar2
. Baz1
trong method baz()
chỉ gọi được trong baz()
mà không gọi được trong Foo1
Mình viết tùm lum ngôn ngữ vậy thì PHP thế nào? Thú thực mình không biết cách PHP thực thi import. Mà mình cũng chắc là tài liệu về cách require
, include
chi tiết cũng ít ai viết. Lý do thì nó thuộc phạm trù của Compiler. Bạn muốn có câu trả lời chỉ có cách đọc PHP specification (tài liệu dành cho dân compiler phát triển PHP, không dành cho dev chỉ có nhu cầu sử dụng), hoặc có khi bạn phải tìm hiểu bộ compiler (kiến trúc, code) tạo ra PHP để trả lời câu hỏi chính xác nhất.